# Test the low-level rbyd data-structure after = 'test_bd' # test with a number of different erase values defines.ERASE_VALUE = [0xff, 0x00, -1] # set block_size to the full size of disk so we can test arbitrarily # large rbyd trees, we don't really care about block sizes at this # abstraction level # # ok not quite full disk size (we do use the full disk size in bench_rbyd), # but a bit less since erasing the full disk takes time and we don't want to # waste time when testing defines.BLOCK_SIZE = 32768 [cases.test_rbyd_atomic_commit] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // commit with one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; // commit with two attributes rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; ''' [cases.test_rbyd_commit] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // commit with one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; // commit with two attributes rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; ''' [cases.test_rbyd_commit_fetch_commit] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // commit with one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; // fetch lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; // commit with the second attribute lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; ''' [cases.test_rbyd_atomic_lookup] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // commit with one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes, in the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_lookup] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // commit with one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes, in the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_atomic_get] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // commit with one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; // commit with two attributes, in the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_get] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // commit with one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; // commit with two attributes, in the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 4; lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_bifoliate] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // create a split in the leaves // .-'| // 1 1 2 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // split the other direction // >b // => .-'| // 2 2 1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_bflips] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // ignore a black edge // .----'| // 1 2 1 2 2 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // flip a black edge // b // .-'| => .-'| // 1 2 1 2 1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_trifoliate] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // ignore a black edge // | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // flip a black edge // >r // .-'| // | >b // .-'| .--|-'| // 2 3 2 3 1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_rflips] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // ignore a red edge and black edge // | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // ignore a red edge, flip a black edge // | >b // | .-'| | .-'| // 1 2 3 1 2 3 2 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // flip a red edge and black edge // r // .----'| .-'| // | | >b // | .-'| .--|-'| // 1 2 3 1 2 3 1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // flip a red edge, ignore a black edge // r // .-'| .-------'| // | >b => | >b // .--|-'| | .-'| // 3 1 2 3 1 2 1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_quadrifoliate] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // ignore a red edge and black edge // | .----'| // | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // ignore a red edge, flip a black edge // y // .-------'| .-'| // r | >r // .----'| => | .-'| => .--|-'| // | b | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // flip a red edge and black edge // >y // .-'| // b // .----'| => .--|-'| // | b // | .-'| .--|--|-'| // 2 3 4 2 3 4 1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // flip a red edge, ignore a black edge // >y // .-------'| // r // .-'| => | .-'| // | >b | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_rotations] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // all three the same // | .----'| // | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // yellow and red alt the same // | .----'| // | b // | .-'| | | .-'| // 1 2 4 1 2 4 3 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // yellow and black alt the same // r | | .----'| => | .-'| // | >b | | b // | .-'| | | .-'| | .--|-'| // 1 4 2 1 4 2 3 1 4 2 3 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // red and black alt the same // >y r | | .----'| => | .-'| // | b // | .-'| | | .-'| .--|--|-'| // 4 1 2 4 1 2 3 4 1 2 3 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_ysplits] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // split a yellow triple, not taking any alt // | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // split a yellow triple, taking the black alt // | b // | | .-'| | | .-'| // 1 2 3 4 1 2 3 4 3 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // split a yellow triple, taking the red alt // b // .-------'| .-'| // | .--------|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // split a yellow triple, taking the yellow alt // b // .-------'| .-'| // | b // | .----'| => .-----|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_quintifoliate] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // split a yellow triple, not taking any alt // | .----' | // | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // split a yellow triple, taking the black alt // | .----' | // | r // | .----'| | | .-'| // | | b // | | .-'| | | .--|-'| // 1 2 4 5 1 2 4 5 3 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // split a yellow triple, taking the red alt // >b // .-'| // b // | .----'| => | .-----|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // split a yellow triple, taking the yellow alt // >b // .-'| // r // .-------'| .-----|-'| // | b // | .----'| => .--|-----|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_prunes] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // don't prune // | .----' | // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // prune by taking a red alt // b // .-------'| | .-'| // | .-----------|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // prune by taking a yellow alt (this needs to prune during the rflip) // b // .-------'| | .-'| // | b // | .----' | => .--------|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_sextifoliate] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // don't prune // | | .-------'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xff\xff\xff\xff"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(6), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(6)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // prune by taking a red alt // b // .-'| .-'| // b // | .----' | => | .--------|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xff\xff\xff\xff"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(6), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(6)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); // prune by taking a yellow alt (this needs to prune during the rflip) // b // .-'| .-'| // r // .-------'| | .--------|-'| // | b // | .----' | => .--|--------|-'| // | | 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xff\xff\xff\xff"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(5)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(6), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(6)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_atomic_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // build the attribute list for the current permutation lfs3_rattr_t rattrs[2*N+1]; lfs3_rattr_t *r = rattrs; for (unsigned j = 0; j < N; j++) { *r++ = LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 4); *r++ = LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"); } *r++ = LFS3_RATTR_NULL; // test the given permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, rattrs) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(j+1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N; printf("--- summary --\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' [cases.test_rbyd_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(j+1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N; printf("--- summary --\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' [cases.test_rbyd_atomic_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; // also try the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; // also try the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_atomic_traverse_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // build the attribute list for the current permutation lfs3_rattr_t rattrs[2*N+1]; lfs3_rattr_t *r = rattrs; for (unsigned j = 0; j < N; j++) { *r++ = LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 4); *r++ = LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"); } *r++ = LFS3_RATTR_NULL; // test the given permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, rattrs) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; // try traversing all tags tag_ = 0; rid_ = -1; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; } ''' [cases.test_rbyd_traverse_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; // try traversing all tags tag_ = 0; rid_ = -1; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_update_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // create one consistent block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(j+1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // restore backup rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // update each tag in permutation order for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } // check that all tags have been updated lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(j+1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 6); } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + N; printf("--- summary --\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' [cases.test_rbyd_large] in = 'lfs3.c' # ORDER: # 0 = in-order # 1 = reverse-order # 2 = random-order defines.ORDER = [0, 1, 2] code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // create the rbyd tree rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; // keep appending tags until we run out of space // // note, this will likely repeat tags, but that's ok // lfs3_size_t count = 0; uint32_t prng = 42; for (lfs3_size_t i = 0;; i++) { lfs3_size_t x = (ORDER == 0) ? i : (ORDER == 1) ? (((lfs3_size_t)-1) - i) : TEST_PRNG(&prng); int err = lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(x & 0x7f), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)); if (err == LFS3_ERR_RANGE) { break; } assert(err == 0); count = i; } // check that we can still lookup all the tags prng = 42; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (lfs3_size_t i = 0; i < count; i++) { lfs3_size_t x = (ORDER == 0) ? i : (ORDER == 1) ? (((lfs3_size_t)-1) - i) : TEST_PRNG(&prng); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(x & 0x7f), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(x & 0x7f)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } ''' ### Removal testing ### [cases.test_rbyd_remove] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // add and remove one attribute rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes, remove the first one rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes, remove the second one rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(2), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_remove_permutations] defines.N = 'range(1, 7)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { // print what we are removing to help debugging printf("--- remove: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(j+1), 0), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(k+1), &rid_, NULL, &data_); if (k == j) { if (j == N-1) { assert(tag_ == LFS3_ERR_NOENT); } else { assert(tag_ == LFS3_TAG_ATTR(j+1+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } } else { assert(tag_ == LFS3_TAG_ATTR(k+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } } // try appending the tag back to make sure things still work printf("--- append: %d ---\n", j); lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(j+1), 0, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(k+1), &rid_, NULL, &data_); if (k == j) { assert(tag_ == LFS3_TAG_ATTR(k+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 6); } else { assert(tag_ == LFS3_TAG_ATTR(k+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + 2; printf("--- summary --\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_remove_traverse_permutations] defines.N = 'range(1, 7)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { // print what we are removing to help debugging printf("--- remove: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(j+1), 0), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; tag_ = 0; rid_ = -1; for (unsigned k = 0; k < N-1; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); if (k >= j) { assert(tag_ == LFS3_TAG_ATTR(k+1+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } else { assert(tag_ == LFS3_TAG_ATTR(k+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; } // cleanup free(backup_block); } ''' [cases.test_rbyd_remove_missing] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // create a tree two attributes rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // try to remove tags that aren't there, this should do nothing lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(3), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(5), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // one last fetch to make sure nothing was broken lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_remove_again] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // create a tree rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; // remove several attributes lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(3), 0), LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(5), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // try to remove tags that aren't there, this should do nothing lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(3), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(5), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // try to remove the tags again, just to make sure (keep in mind // these removes still commit to the rbyd) lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(3), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(5), 0), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // one last fetch to make sure nothing was broken lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(4), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(4)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(5), &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_remove_all] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_ssize_t rid_; lfs3_data_t data_; // commit with one attribute, remove it rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes, remove both rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(2), 0), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; // commit with two attributes, remove both in the other order rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(2), 0), LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2), &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_remove_all_permutations] defines.N = 'range(1, 7)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // create one consistent block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(j+1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // restore backup rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // remove each tag in permutation order for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(perm[j]+1), 0), LFS3_RATTR_NULL)) => 0; } // check that all tags are now removed lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(j+1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; } // try resuming from all tags being removed lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 6); for (unsigned j = 1; j < N; j++) { lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(j+1), &rid_, NULL, &data_) => LFS3_ERR_NOENT; } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + N + 1; printf("--- summary --\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # the main purpose of this test is to try to fuzz for failures in the # balancing algorithm [cases.test_rbyd_fuzz_append_removes] defines.N = 'range(1, 33)' defines.SEED = 'range(1000)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag; lfs3_data_t data; uint8_t buffer[4]; printf("perm: ["); uint32_t prng = SEED; for (unsigned i = 0; i < N; i++) { // choose an rattr uint8_t rattr = TEST_PRNG(&prng) % N; // choose append or remove if (TEST_PRNG(&prng) & 1) { printf("a0x%02x=%c", rattr, 'a'+(i % 26)); } else { printf("r0x%02x", rattr); } if (i < N-1) { printf(", "); } } printf("]\n"); // set up a simulation to compare against char *sim = malloc(N); memset(sim, 0, N); // set up rbyd block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; prng = SEED; for (unsigned i = 0; i < N; i++) { // choose an rattr uint8_t rattr = TEST_PRNG(&prng) % N; // choose append or remove if (TEST_PRNG(&prng) & 1) { // update our sim sim[rattr] = 'a'+(i % 26); // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(rattr), 0, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(&(uint8_t){'a'+(i % 26)}), LFS3_RATTR_NULL)) => 0; } else { // update our sim sim[rattr] = '\0'; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(rattr), 0), LFS3_RATTR_NULL)) => 0; } } // compare rbyd vs simulation printf("expd: ["); bool first = true; for (unsigned rattr = 0; rattr < N; rattr++) { if (sim[rattr]) { if (!first) { printf(", "); } first = false; printf("0x%02x=%c", rattr, sim[rattr]); } } printf("]\n"); printf("rbyd: ["); first = true; for (unsigned rattr = 0; rattr < N; rattr++) { tag = lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(rattr), &data); if (tag >= 0) { lfs3_ssize_t size = lfs3_data_read(&lfs3, &data, buffer, 4); if (!first) { printf(", "); } first = false; printf("0x%02x=%.*s", rattr, size, buffer); } } printf("]\n"); for (unsigned rattr = 0; rattr < N; rattr++) { tag = lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(rattr), &data); if (sim[rattr]) { assert(tag == LFS3_TAG_ATTR(rattr)); lfs3_ssize_t size = lfs3_data_read(&lfs3, &data, buffer, 4); assert(size == 1); assert(memcmp(&sim[rattr], buffer, 1) == 0); } else { assert(tag == LFS3_ERR_NOENT); } } // cleanup free(sim); ''' ### Insertion testing ### [cases.test_rbyd_atomic_create] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // try to create one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); // try to create two ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); // create a third to the right rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); ''' [cases.test_rbyd_create] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // try to create one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); // try to create two ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); // try to create two in the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); // create a third to the right rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); // create a third to the left rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); // create a third in the middle rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); ''' [cases.test_rbyd_create_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[4]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' [cases.test_rbyd_atomic_create_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 00000000, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_create_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; // also try the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_create_traverse_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); // try traversing all tags tag_ = 0; rid_ = -1; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; } ''' [cases.test_rbyd_create_large] in = 'lfs3.c' # ORDER: # 0 = in-order # 1 = reverse-order # 2 = random-order defines.ORDER = [0, 1, 2] code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // create the rbyd tree rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; // keep inserting tags until we run out of space // // note, the ids we create this way are both sparse and sometimes // repeated, so we need to mod our current rbyd size to avoid invalid // insertions // uint32_t prng = 42; for (lfs3_size_t i = 0;; i++) { uint16_t x = (ORDER == 0) ? (uint16_t)i : (ORDER == 1) ? (uint16_t)(((lfs3_size_t)-1) - i) : (uint16_t)TEST_PRNG(&prng); x = x % (rbyd.weight+1); int err = lfs3_rbyd_commit(&lfs3, &rbyd, x, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[x % 6]), LFS3_RATTR_NULL)); if (err == LFS3_ERR_RANGE) { break; } assert(err == 0); } // check that we can at least lookup all the tags // // note with random order we can't check that stored values reliably lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (uint16_t x = 0; x < rbyd.weight; x++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, x, LFS3_TAG_DATA, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == x); assert(lfs3_data_size(data_) == 4); } ''' ### Mixed create and rattr testing ### [cases.test_rbyd_atomic_mixed] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // try to create one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); // try to create two ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); // create a third to the right rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); ''' [cases.test_rbyd_mixed] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // try to create one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); // try to create two ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); // try to create two in the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); // create a third to the right rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); // create a third to the left rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); // create a third in the middle rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); ''' [cases.test_rbyd_mixed_permutations] defines.N = 'range(1, 7)' defines.M = 'range(1, 4)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[4]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_ATTR(u+1), &data) => LFS3_TAG_ATTR(u+1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, names[j % 6], 2) == 0); } } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + N*M; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' [cases.test_rbyd_atomic_mixed_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 1); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 1); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_mixed_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 1); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 1); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; // also try the other direction rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 1); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 1); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_mixed_traverse_permutations] defines.N = 'range(1, 7)' defines.M = 'range(1, 4)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); // try traversing all tags tag_ = 0; rid_ = -1; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(u+1)); assert(rid_ == j); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, names[j % 6], 2) == 0); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_mixed_update_permutations] defines.N = 'range(1, 4)' defines.M = 'range(1, 3)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // create one consistent block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; } } // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N*M); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N*M]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N*M); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N*M; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // restore backup rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // update each tag in permutation order for (unsigned j = 0; j < N*M; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, perm[j]/M, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]%M+1), 0, LFS3_FROM_BUF, 3), LFS3_RATTR_ARG(names[(perm[j]/M) % 6]), LFS3_RATTR_NULL)) => 0; } // check that all tags have been updated lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_ATTR(u+1), &data) => LFS3_TAG_ATTR(u+1); lfs3_data_read(&lfs3, &data, buffer, 4) => 3; assert(memcmp(buffer, names[j % 6], 3) == 0); } } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + N*M + N*M; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_mixed_remove_permutations] defines.N = 'range(1, 7)' defines.M = 'range(1, 4)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } } // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try removing each tag for (unsigned j = 0; j < N*M; j++) { // print what we are removing to help debugging printf("--- remove: rid%jd, %jd ---\n", j/M, (j%M)+1); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j/M, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR((j%M)+1), 0), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; for (unsigned k = 0; k < N; k++) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k, LFS3_TAG_ATTR(u+1), &rid_, NULL, &data_); if (k == j/M && u == j%M) { if (u == M-1 && k == N-1) { assert(tag_ == LFS3_ERR_NOENT); } else if (u == M-1) { assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k+1); assert(lfs3_data_size(data_) == 4); } else { assert(tag_ == LFS3_TAG_ATTR(u+1+1)); assert(rid_ == k); assert(lfs3_data_size(data_) == 2); } } else { assert(tag_ == LFS3_TAG_ATTR(u+1)); assert(rid_ == k); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, names[k % 6], 2) == 0); } } } // try append the tag back to make sure things still work printf("--- append: rid%jd, %jd ---\n", j/M, (j%M)+1); lfs3_rbyd_commit(&lfs3, &rbyd, j/M, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR((j%M)+1), 0, LFS3_FROM_BUF, 3), LFS3_RATTR_ARG(names[(j/M)%6]), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; for (unsigned k = 0; k < N; k++) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k, LFS3_TAG_ATTR(u+1), &rid_, NULL, &data_); if (k == j/M && u == j%M) { assert(tag_ == LFS3_TAG_ATTR(u+1)); assert(rid_ == k); assert(lfs3_data_size(data_) == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 3; assert(memcmp(buffer, names[k % 6], 3) == 0); } else { assert(tag_ == LFS3_TAG_ATTR(u+1)); assert(rid_ == k); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, names[k % 6], 2) == 0); } } } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N+N*M + 2; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_mixed_remove_all_permutations] defines.N = 'range(1, 4)' defines.M = 'range(1, 3)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // create one consistent block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; } } // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N*M); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N*M]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N*M); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N*M; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // restore backup rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // remove each tag in permutation order for (unsigned j = 0; j < N*M; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, perm[j]/M, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(perm[j]%M+1), 0), LFS3_RATTR_NULL)) => 0; } // check that all tags have been removed lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_ATTR(u+1), &data) => LFS3_ERR_NOENT; } } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + N*M + N*M; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' [cases.test_rbyd_mixed_large] in = 'lfs3.c' # ORDER: # 0 = in-order # 1 = reverse-order # 2 = random-order defines.ORDER = [0, 1, 2] defines.M = 'range(1, 4)' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // create the rbyd tree rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; // keep inserting tags until we run out of space // // note, the ids we create this way are both sparse and sometimes // repeated, so we need to mod our current rbyd size to avoid invalid // insertions // uint32_t prng = 42; for (lfs3_size_t i = 0;; i++) { uint16_t x = (ORDER == 0) ? (uint16_t)i : (ORDER == 1) ? (uint16_t)(((lfs3_size_t)-1) - i) : (uint16_t)TEST_PRNG(&prng); x = x % (rbyd.weight+1); // build a single attribute list with all ratibutes, if this fails // it should fail atomically lfs3_rattr_t rattrs[2+2*M+1]; lfs3_rattr_t *r = rattrs; *r++ = LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4); *r++ = LFS3_RATTR_ARG(names[x % 6]); for (unsigned u = 0; u < M; u++) { *r++ = LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2); *r++ = LFS3_RATTR_ARG(names[x % 6]); } *r++ = LFS3_RATTR_NULL; int err = lfs3_rbyd_commit(&lfs3, &rbyd, x, rattrs); if (err == LFS3_ERR_RANGE) { break; } assert(err == 0); } // check that we can at least lookup all the tags // // note with random order we can't check that stored values reliably lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; for (uint16_t x = 0; x < rbyd.weight; x++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, x, LFS3_TAG_DATA, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == x); assert(lfs3_data_size(data_) == 4); for (unsigned u = 0; u < M; u++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, x, LFS3_TAG_ATTR(u+1), &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(u+1)); assert(rid_ == x); assert(lfs3_data_size(data_) == 2); } } ''' ### Test unrelated no-rid tags ### [cases.test_rbyd_unrelated_create_permutations] defines.N = 'range(1, 8)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[4]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // note the data size differences here lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } // try looking up each tag lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(j+1), &data) => LFS3_TAG_ATTR(j+1); lfs3_data_read(&lfs3, &data, buffer, 4) => 1; assert(memcmp(buffer, names[j % 6], 1) == 0); } for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } // try traversing tags lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_data_t data_; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 1; assert(memcmp(buffer, names[j % 6], 1) == 0); } for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' [cases.test_rbyd_unrelated_mixed_permutations] defines.N = 'range(1, 7)' defines.M = 'range(1, 4)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[4]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // note the data size differences here lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(perm[j]+1), 0, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } } // try looking up each tag lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(j+1), &data) => LFS3_TAG_ATTR(j+1); lfs3_data_read(&lfs3, &data, buffer, 4) => 1; assert(memcmp(buffer, names[j % 6], 1) == 0); } for (unsigned j = 0; j < N; j++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_TAG_ATTR(u+1), &data) => LFS3_TAG_ATTR(u+1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, names[j % 6], 2) == 0); } } // try traversing tags lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_data_t data_; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(j+1)); assert(rid_ == -1); assert(lfs3_data_size(data_) == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 1; assert(memcmp(buffer, names[j % 6], 1) == 0); } for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(u+1)); assert(rid_ == j); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, names[j % 6], 2) == 0); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + N*M; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' ### Deletion testing ### [cases.test_rbyd_delete] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // try to delete one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // try to delete the other rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // try to delete the largest of three rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // try to delete the smallest of three rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // try to delete the middle rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // try to delete one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to delete the other rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to delete the largest of three rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to delete the smallest of three rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to delete the middle rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' # some additional delete range special cases [cases.test_rbyd_delete_range_b] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .-------o-------. // .---o---. .---o---. // .-o-. .-o-. .-o-. .-o-. // .o. .o. .o. .o. .o. .o. .o. .o. // a a a a a a a c c e e e e e e e // '-+-' // remove // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_r] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .-------o-------. // .---r----. .----r---. // .o. .o. .-r-. .-r-. .o. .o. // a a a a a a c c e e e e e e // '-+-' // remove // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_y] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .-------------o-------------. // .---y---+------. .------+---y---. // .o. .o. .o. .-+-y-. .-y-+-. .o. .o. .o. // a a a a a a a a a c c e e e e e e e e e // '-+-' // remove // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(8), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(8), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydy] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .-------------r-------------. // .-o-. .----y---+---. .-o-. // .o. .o. .-+-y-. .o. .o. .o. .o. .o. // a a a a a a a c e e e e e e e e e e // '+' // remove // // this is a specific nasty case where tail-recursion can be // violated if you preserve coloring during range removes // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(8), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(9), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(9), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(9), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydy_backwards] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .-------------r-------------. // .-o-. .---+---y----. .-o-. // .o. .o. .o. .o. .o. .-y-+-. .o. .o. // a a a a a a a a a a c e e e e e e e // '+' // remove // // this is a specific nasty case where tail-recursion can be // violated if you preserve coloring during range removes // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(9), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(8), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(8), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydye] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .-------------r-------------. // .-o-. .----y---+---. .-o-. // .o. .o. .-+-y-. .o. .o. .o. .o. .o. // a a a a a a a c c c e e e e e e e e // '--+--' // remove // // this is a specific nasty case where tail-recursion can be // violated if you preserve coloring during range removes // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_rydye_backwards] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .-------------r-------------. // .-o-. .---+---y----. .-o-. // .o. .o. .o. .o. .o. .-y-+-. .o. .o. // a a a a a a a a c c c e e e e e e e // '--+--' // remove // // this is a specific nasty case where tail-recursion can be // violated if you preserve coloring during range removes // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_dryy] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // o---------------------. // .-------+---------r .---o---. // .-o-. .-o-. .---y------+----. .-o-. .-o-. // .o. .o. .o. .o. .o. .o. .-+-y-. .o. .o. .o. .o. .o. // a a a a a a a a a a a a a a a c c c c e e e e e e e // '---+---' // remove // // this is an attempt at colliding two splits by pruning after // diverging, in theory this can lead to tail-recursion violations, // but no violations have been found to be possible yet // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(8), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(11), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(12), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(13), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(14), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(9), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(10), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(10), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_range_dryy_backwards] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; uint8_t buffer[4]; // delete inner branches // // .---------------------o // .---o---. r---------+-------. // .-o-. .-o-. .----+------y---. .-o-. .-o-. // .o. .o. .o. .o. .o. .-y-+-. .o. .o. .o. .o. .o. .o. // a a a a a a a c c c c e e e e e e e e e e e e e e e // '---+---' // remove // // this is an attempt at colliding two splits by pruning after // diverging, in theory this can lead to tail-recursion violations, // but no violations have been found to be possible yet // rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(6), +1, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(7), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(8), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(9), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(10), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow to the root LFS3_RATTR(2, LFS3_TAG_ATTR(10), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(10), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(10), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // this gets a bit messy as we try to make the rbyd take the right shape lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(11), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(12), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(13), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(14), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(14), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(14), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_DATA, 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(5), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), // propagate yellow LFS3_RATTR(2, LFS3_TAG_ATTR(4), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try to recreate lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 3); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &data) => LFS3_TAG_ATTR(1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &data) => LFS3_TAG_ATTR(2); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(3), &data) => LFS3_TAG_ATTR(3); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(4), &data) => LFS3_TAG_ATTR(4); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(5), &data) => LFS3_TAG_ATTR(5); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(6), &data) => LFS3_TAG_ATTR(6); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(7), &data) => LFS3_TAG_ATTR(7); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(8), &data) => LFS3_TAG_ATTR(8); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(9), &data) => LFS3_TAG_ATTR(9); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(10), &data) => LFS3_TAG_ATTR(10); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(11), &data) => LFS3_TAG_ATTR(11); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(12), &data) => LFS3_TAG_ATTR(12); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(13), &data) => LFS3_TAG_ATTR(13); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(14), &data) => LFS3_TAG_ATTR(14); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; assert(memcmp(buffer, "\xee\xee", 2) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 3, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_delete_permutations] defines.N = 'range(1, 7)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[6]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each delete lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try deleting each rid for (unsigned j = 0; j < N; j++) { // print what we are deleting to help debugging printf("--- delete: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N-1); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N-1); for (unsigned k = 0; k < N-1; k++) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 4) == 0); } else { assert(memcmp(buffer, names[k % 6], 4) == 0); } } lfs3_rbyd_lookup(&lfs3, &rbyd, N-1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // try recreating the rid to make sure things still work printf("--- create: %d ---\n", j); lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N); for (unsigned k = 0; k < N; k++) { if (k == j) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, names[k % 6], 6) == 0); } else { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N + 2; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_delete_range_permutations] defines.N = 'range(1, 7)' defines.M = 'range(1, 4)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[6]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } } assert(rbyd.weight == N); // copy block so we can reset after each delete lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try deleting each rid for (unsigned j = 0; j < N; j++) { // print what we are deleting to help debugging printf("--- delete: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N-1); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N-1); for (unsigned k = 0; k < N-1; k++) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 4) == 0); } else { assert(memcmp(buffer, names[k % 6], 4) == 0); } for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_ATTR(u+1), &data) => LFS3_TAG_ATTR(u+1); lfs3_data_read(&lfs3, &data, buffer, 4) => 2; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 2) == 0); } else { assert(memcmp(buffer, names[k % 6], 2) == 0); } } } lfs3_rbyd_lookup(&lfs3, &rbyd, N-1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, N-1, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // try recreating the rid to make sure things still work printf("--- create: %d ---\n", j); lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 3), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N); for (unsigned k = 0; k < N; k++) { if (k == j) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, names[k % 6], 6) == 0); for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_ATTR(u+1), &data) => LFS3_TAG_ATTR(u+1); lfs3_data_read(&lfs3, &data, buffer, 6) => 3; assert(memcmp(buffer, names[k % 6], 3) == 0); } } else { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_TAG_ATTR(u+1), &data) => LFS3_TAG_ATTR(u+1); lfs3_data_read(&lfs3, &data, buffer, 6) => 2; assert(memcmp(buffer, names[k % 6], 2) == 0); } } } // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); } // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N+N*M + 1 + 1+M; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_delete_traverse_permutations] defines.N = 'range(1, 7)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each delete lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try deleting each rid for (unsigned j = 0; j < N; j++) { // print what we are deleting to help debugging printf("--- delete: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N-1); // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N-1); tag_ = 0; rid_ = -1; for (unsigned k = 0; k < N-1; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 4) == 0); } else { assert(memcmp(buffer, names[k % 6], 4) == 0); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; } // cleanup free(backup_block); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_delete_traverse_range_permutations] defines.N = 'range(1, 7)' defines.M = 'range(1, 4)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } } assert(rbyd.weight == N); // copy block so we can reset after each delete lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try deleting each rid for (unsigned j = 0; j < N; j++) { // print what we are deleting to help debugging printf("--- delete: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N-1); // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N-1); tag_ = 0; rid_ = -1; for (unsigned k = 0; k < N-1; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 4) == 0); } else { assert(memcmp(buffer, names[k % 6], 4) == 0); } for (unsigned u = 0; u < M; u++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_); assert(tag_ == LFS3_TAG_ATTR(u+1)); assert(rid_ == k); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 2; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 2) == 0); } else { assert(memcmp(buffer, names[k % 6], 2) == 0); } } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, NULL, &data_) => LFS3_ERR_NOENT; } // cleanup free(backup_block); } ''' # Note, "delete_all" is a weird state for rbyd trees to be in, since they # don't really have a trunk at this point [cases.test_rbyd_delete_all] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; // create and delete one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete two ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete two ids in the other order rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete three ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete three ids in the other order rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_delete_all_range] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_data_t data; // create and delete one rid rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete two ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete two ids in the other order rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete three ids rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 2, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // create and delete three ids in the other order rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_delete_all_permutations] defines.N = 'range(1, 7)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[6]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // create one consistent block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each delete lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // restore backup rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // delete each rid in permutation order for (unsigned j = 0; j < N; j++) { // adjust rid based on previous deletions uint16_t rid = perm[j]; for (unsigned k = 0; k < j; k++) { if (perm[k] < perm[j]) { rid -= 1; } } lfs3_size_t rbyd_weight_before = rbyd.weight; lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == rbyd_weight_before-1); } // check that all tags are now removed lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, LFS3_TAG_DATA, 0, &data) => LFS3_ERR_NOENT; // try resuming from all tags being removed lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + 2*N + 1; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_delete_all_range_permutations] defines.N = 'range(1, 7)' defines.M = 'range(1, 4)' # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_data_t data; uint8_t buffer[6]; // keep track of the worst case log size lfs3_size_t worst_size = 0; size_t worst_perm_i = 0; // create one consistent block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; // note uattrs have a smaller size to help debugging for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; } } assert(rbyd.weight == N); // copy block so we can reset after each delete lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // restore backup rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // delete each rid in permutation order for (unsigned j = 0; j < N; j++) { // adjust rid based on previous deletions uint16_t rid = perm[j]; for (unsigned k = 0; k < j; k++) { if (perm[k] < perm[j]) { rid -= 1; } } lfs3_size_t rbyd_weight_before = rbyd.weight; lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == rbyd_weight_before-1); } // check that all tags are now removed lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 0); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; // try resuming from all tags being removed lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; for (unsigned u = 0; u < M; u++) { lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u+1), 0, LFS3_FROM_BUF, 3), LFS3_RATTR_ARG("\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == 1); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == 1); lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0); for (unsigned u = 0; u < M; u++) { lfs3_rbyd_lookup(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(u+1), &data) => LFS3_TAG_ATTR(u+1); lfs3_data_read(&lfs3, &data, buffer, 6) => 3; assert(memcmp(buffer, "\xaa\xaa\xaa", 3) == 0); } lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_DATA, &data) => LFS3_ERR_NOENT; lfs3_rbyd_lookup(&lfs3, &rbyd, 1, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; // keep track of the worst size if (lfs3_rbyd_eoff(&rbyd) > worst_size) { worst_size = lfs3_rbyd_eoff(&rbyd); worst_perm_i = perm_i; } } // cleanup free(backup_block); // test that tree is self-balancing, we should be strictly bounded // by height <= 2*log(n)+1, assume tags are strictly <=12 bytes lfs3_size_t n = 1 + N+N*M + N + 1+M; printf("--- summary ---\n"); printf("worst permutation: %zd\n", worst_perm_i); printf("worst size: %u B (N=%u, estimate=%u)\n", worst_size, n, 12*n*(2*lfs3_nlog2(n)+1)+4); printf("worst avg height: %u B (N=%u, estimate=%u)\n", worst_size / n, n, 12*(2*lfs3_nlog2(n)+1)+4); // note this only holds true with byte-level progs if (PROG_SIZE == 1) { assert(worst_size / n <= 12*(2*lfs3_nlog2(n)+1)+4); } ''' # the main purpose of this test is to try to fuzz for failures in the # balancing algorithm [cases.test_rbyd_fuzz_create_deletes] defines.N = 'range(1, 33)' defines.SEED = 'range(1000)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag; lfs3_data_t data; uint8_t buffer[4]; printf("perm: ["); uint32_t prng = SEED; lfs3_size_t count = 0; for (unsigned i = 0; i < N; i++) { // choose an rid lfs3_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose create or delete if (rid == (lfs3_ssize_t)count || (TEST_PRNG(&prng) & 1)) { printf("c%d=%c", rid, 'a'+(i % 26)); count += 1; } else { printf("d%d", rid); count -= 1; } if (i < N-1) { printf(", "); } } printf("]\n"); // set up a simulation to compare against, fun fact this performs // worst than our actual rbyd block! char *sim = malloc(N); memset(sim, 0, N); // set up rbyd block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; prng = SEED; count = 0; for (unsigned i = 0; i < N; i++) { // choose an rid lfs3_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose create or delete if (rid == (lfs3_ssize_t)count || (TEST_PRNG(&prng) & 1)) { // update our sim memmove(sim+rid+1, sim+rid, count-rid); sim[rid] = 'a'+(i % 26); count += 1; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(&(uint8_t){'a'+(i % 26)}), LFS3_RATTR_NULL)) => 0; } else { // update our sim memmove(sim+rid, sim+rid+1, count-rid-1); count -= 1; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; } } // compare rbyd vs simulation printf("expd: ["); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)count; rid++) { printf("%c", sim[rid]); if (rid < (lfs3_ssize_t)count-1) { printf(", "); } } printf("]\n"); printf("rbyd: ["); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)rbyd.weight; rid++) { tag = lfs3_rbyd_lookup(&lfs3, &rbyd, rid, LFS3_TAG_DATA, &data); if (tag >= 0) { lfs3_ssize_t size = lfs3_data_read(&lfs3, &data, buffer, 4); printf("%.*s", size, buffer); } else { printf("?"); } if (rid < (lfs3_ssize_t)count-1) { printf(", "); } } printf("]\n"); assert(count == rbyd.weight); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)count; rid++) { lfs3_rbyd_lookup(&lfs3, &rbyd, rid, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 1; assert(memcmp(&sim[rid], buffer, 1) == 0); } // cleanup free(sim); ''' # Test rbyd weights [cases.test_rbyd_sparse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; // make id0 with weight w1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); // make id2 with weight w2 lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+2), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); // make id5 with weight w3 lfs3_rbyd_commit(&lfs3, &rbyd, 3, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+3), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); // make id9 with weight w4 lfs3_rbyd_commit(&lfs3, &rbyd, 6, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); // make id14 with weight w5 lfs3_rbyd_commit(&lfs3, &rbyd, 10, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+5), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); ''' [cases.test_rbyd_sparse_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( // make id0 with weight w1 LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), // make id2 with weight w2 LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+2), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), // make id5 with weight w3 LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+3), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), // make id9 with weight w4 LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), // make id14 with weight w5 LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+5), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR_NULL)) => 0; // traverse, finding tags and weights tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_sparse_permutations] defines.N = 'range(1, 8)' defines.W = 5 # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N*W); for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, j*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, j*W+W-1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } } ''' [cases.test_rbyd_sparse_traverse_permutations] defines.N = 'range(1, 8)' defines.W = 5 # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N*W); // try traversing all tags tag_ = 0; rid_ = -1; for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; } ''' # Weights mixed with attributes [cases.test_rbyd_sparse_mixed] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; // make id0 with weight w1 rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 9), LFS3_RATTR_ARG("unrelated"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); // make id2 with weight w2 lfs3_rbyd_commit(&lfs3, &rbyd, 1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(1, LFS3_tag_GROW, +1), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); // make id5 with weight w3 lfs3_rbyd_commit(&lfs3, &rbyd, 3, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+2), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); // make id9 with weight w4 lfs3_rbyd_commit(&lfs3, &rbyd, 6, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xdd\xdd"), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+3), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xdd\xdd"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); // make id14 with weight w5 lfs3_rbyd_commit(&lfs3, &rbyd, 10, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+4), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 2, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 5, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 9, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, 14, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); ''' [cases.test_rbyd_sparse_mixed_traverse] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 9), LFS3_RATTR_ARG("unrelated"), // make id0 with weight w1 LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xaa\xaa"), // make id2 with weight w2 LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), LFS3_RATTR(1, LFS3_tag_GROW, +1), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xbb\xbb"), // make id5 with weight w3 LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+2), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xcc\xcc"), // make id9 with weight w4 LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xdd\xdd"), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+3), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xdd\xdd"), // make id14 with weight w5 LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xee\xee\xee\xee"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+4), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG("\xee\xee"), LFS3_RATTR_NULL)) => 0; // traverse, finding tags and weights tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 0); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 0); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 2); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 2); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 5); assert(weight_ == 3); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 5); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 9); assert(weight_ == 4); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 9); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == 14); assert(weight_ == 5); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == 14); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_sparse_mixed_permutations] defines.N = 'range(1, 8)' defines.W = 5 # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 9), LFS3_RATTR_ARG("unrelated"), LFS3_RATTR_NULL)) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+W-1), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N*W); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(3), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, j*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, j*W+W-1, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == j*W+W-1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, j*W+W-1, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == j*W+W-1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); lfs3_rbyd_lookup(&lfs3, &rbyd, j*W+W-1, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } } ''' [cases.test_rbyd_sparse_mixed_traverse_permutations] defines.N = 'range(1, 8)' defines.W = 5 # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(3), 0, LFS3_FROM_BUF, 9), LFS3_RATTR_ARG("unrelated"), LFS3_RATTR_NULL)) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+W-1), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N*W); // try traversing all tags tag_ = 0; rid_ = -1; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(3)); assert(rid_ == -1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 9); for (unsigned j = 0; j < N; j++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == j*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == j*W+W-1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == j*W+W-1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; } ''' # other sparse testing, various grow/shrink corner cases [cases.test_rbyd_sparse_grow_permutations] defines.N = 'range(1, 7)' defines.W = 5 defines.D = [1, 2] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try growing each rid for (unsigned j = 0; j < N; j++) { // print what we are growing to help debugging printf("--- growing: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+D), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W+D); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W+D); for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1+D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1+D); assert(weight_ == W+D); assert(lfs3_data_size(data_) == 4); } else if (k > j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1+D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1+D); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); } lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } } ''' [cases.test_rbyd_sparse_grupdate_permutations] defines.N = 'range(1, 7)' defines.W = 5 defines.D = [1, 2] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[6]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try growing each rid for (unsigned j = 0; j < N; j++) { // print what we are growing to help debugging printf("--- growing: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(3, LFS3_tag_GROW | LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 6), LFS3_RATTR_WEIGHT(+D), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W+D); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W+D); for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1+D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1+D); assert(weight_ == W+D); assert(lfs3_data_size(data_) == 6); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, names[k % 6], 6) == 0); } else if (k > j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1+D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1+D); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } } } ''' # I don't know if this actually happens in littlefs, but this tests a specific # code path in lfs3_rbyd_append (split altgt + shrinking) [cases.test_rbyd_sparse_grappend_permutations] defines.N = 'range(1, 7)' defines.W = 5 defines.D = [1, 2] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[6]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_ATTR(2), -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try growing each rid for (unsigned j = 0; j < N; j++) { // print what we are growing to help debugging printf("--- growing: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(3, LFS3_tag_GROW | LFS3_TAG_ATTR(1), -2, LFS3_FROM_BUF, 6), LFS3_RATTR_WEIGHT(+D), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W+D); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W+D); for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1+D, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == k*W+W-1+D); assert(weight_ == W+D); assert(lfs3_data_size(data_) == 6); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, names[k % 6], 6) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1+D, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == k*W+W-1+D); assert(weight_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } else if (k > j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1+D, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == k*W+W-1+D); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } } } ''' [cases.test_rbyd_sparse_shrink_permutations] defines.N = 'range(1, 7)' defines.W = 5 defines.D = [1, 2] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try shrinking each rid for (unsigned j = 0; j < N; j++) { // print what we are shrinking to help debugging printf("--- shrinking: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(-D), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W-D); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W-D); for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1-D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1-D); assert(weight_ == W-D); assert(lfs3_data_size(data_) == 4); } else if (k > j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1-D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1-D); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); } lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } } ''' [cases.test_rbyd_sparse_shrupdate_permutations] defines.N = 'range(1, 7)' defines.W = 5 defines.D = [1, 2] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[6]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try shrinking each rid for (unsigned j = 0; j < N; j++) { // print what we are shrinking to help debugging printf("--- shrinking: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(3, LFS3_tag_GROW | LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 6), LFS3_RATTR_WEIGHT(-D), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W-D); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W-D); for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1-D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1-D); assert(weight_ == W-D); assert(lfs3_data_size(data_) == 6); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, names[k % 6], 6) == 0); } else if (k > j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1-D, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1-D); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } } } ''' # I don't know if this actually happens in littlefs, but this tests a specific # code path in lfs3_rbyd_append (split altgt + shrinking) [cases.test_rbyd_sparse_shrappend_permutations] defines.N = 'range(1, 7)' defines.W = 5 defines.D = [1, 2] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[6]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_ATTR(2), -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try shrinking each rid for (unsigned j = 0; j < N; j++) { // print what we are shrinking to help debugging printf("--- shrinking: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(3, LFS3_tag_GROW | LFS3_TAG_ATTR(1), -2, LFS3_FROM_BUF, 6), LFS3_RATTR_WEIGHT(-D), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W-D); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W-D); for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1-D, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == k*W+W-1-D); assert(weight_ == W-D); assert(lfs3_data_size(data_) == 6); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, names[k % 6], 6) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1-D, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == k*W+W-1-D); assert(weight_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } else if (k > j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1-D, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == k*W+W-1-D); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_ATTR(2), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(2)); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } } } ''' [cases.test_rbyd_sparse_delete_permutations] defines.N = 'range(1, 7)' defines.W = 5 # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[6]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try deleting each rid for (unsigned j = 0; j < N; j++) { // print what we are deleting to help debugging printf("--- deleting: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_RM, -2), LFS3_RATTR_WEIGHT(-W), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == (N-1)*W); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == (N-1)*W); for (unsigned k = 0; k < N-1; k++) { if (k >= j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[(k+1) % 6], 4) == 0); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } // try recreating the rid to make sure things still work printf("--- create: %d ---\n", j); lfs3_rbyd_commit(&lfs3, &rbyd, j*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 6), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W); for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 6); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 6; assert(memcmp(buffer, names[k % 6], 6) == 0); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 6) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); } } } } ''' [cases.test_rbyd_sparse_rattr_permutations] defines.N = 'range(1, 7)' defines.W = 5 # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } lfs3_rbyd_commit(&lfs3, &rbyd, rid*W, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 4), LFS3_RATTR_WEIGHT(+W), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N*W); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try appending an rattr to each rid, this should not affect // weights at all! for (unsigned j = 0; j < N; j++) { // print what we are appending to help debugging printf("--- appending: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W); for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == k*W+W-1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } } // now try removing the rattr printf("--- removing: %d ---\n", j); lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W); for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); if (k == j) { lfs3_rbyd_lookup(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_ATTR(1), &data) => LFS3_ERR_NOENT; } } // and try putting the rattr back just for good measure printf("--- appending: %d ---\n", j); lfs3_rbyd_commit(&lfs3, &rbyd, j*W+W-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == N*W); lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; assert(rbyd.weight == N*W); for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_DATA); assert(rid_ == k*W+W-1); assert(weight_ == W); assert(lfs3_data_size(data_) == 4); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 4; assert(memcmp(buffer, names[k % 6], 4) == 0); if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, k*W+W-1, LFS3_TAG_ATTR(1), &rid_, &weight_, &data_); assert(tag_ == LFS3_TAG_ATTR(1)); assert(rid_ == k*W+W-1); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } } } } ''' # Some more fuzzish testing [cases.test_rbyd_fuzz_mixed] defines.N = 'range(1, 33)' defines.M = 3 defines.SEED = 'range(1000)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag; lfs3_data_t data; uint8_t buffer[4]; printf("perm: ["); uint32_t prng = SEED; lfs3_size_t count = 0; for (unsigned i = 0; i < N; i++) { // choose create/delete or rattr append/remove uint8_t op = TEST_PRNG(&prng) % 4; // choose an rid lfs3_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose an rattr uint8_t u = TEST_PRNG(&prng) % M; if (rid == (lfs3_ssize_t)count || op == 0) { printf("c%d=%c", rid, 'a'+(i % 26)); count += 1; } else if (op == 1) { printf("d%d", rid); count -= 1; } else if (op == 2) { printf("a%d,%d=%c", rid, u, 'a'+(i % 26)); } else if (op == 3) { printf("r%d,%d", rid, u); } if (i < N-1) { printf(", "); } } printf("]\n"); // set up a simulation to compare against, fun fact this performs // worst than our actual rbyd block! char *sim = malloc(N*(M+1)); memset(sim, 0, N*(M+1)); // set up rbyd block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; prng = SEED; count = 0; for (unsigned i = 0; i < N; i++) { // choose create/delete or rattr append/remove uint8_t op = TEST_PRNG(&prng) % 4; // choose an rid lfs3_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose an rattr uint8_t u = TEST_PRNG(&prng) % M; if (rid == (lfs3_ssize_t)count || op == 0) { // update our sim memmove(sim+(rid+1)*(M+1), sim+rid*(M+1), (count-rid)*(M+1)); memset(&sim[rid*(M+1)], 0, M+1); sim[rid*(M+1)] = 'a'+(i % 26); count += 1; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(&(uint8_t){'a'+(i % 26)}), LFS3_RATTR_NULL)) => 0; } else if (op == 1) { // update our sim memmove(sim+rid*(M+1), sim+(rid+1)*(M+1), (count-rid-1)*(M+1)); count -= 1; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; } else if (op == 2) { // update our sim sim[rid*(M+1) + u+1] = 'a'+(i % 26); // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(u), 0, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(&(uint8_t){'a'+(i % 26)}), LFS3_RATTR_NULL)) => 0; } else if (op == 3) { // update our sim sim[rid*(M+1) + u+1] = '\0'; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(u), 0), LFS3_RATTR_NULL)) => 0; } } // compare rbyd vs simulation printf("expd: ["); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)count; rid++) { printf("%c", sim[rid*(M+1)]); for (uint8_t u = 0; u < M; u++) { if (sim[rid*(M+1) + u+1]) { printf("%c", sim[rid*(M+1) + u+1]); } else { printf("_"); } } if (rid < (lfs3_ssize_t)count-1) { printf(", "); } } printf("]\n"); printf("rbyd: ["); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)rbyd.weight; rid++) { tag = lfs3_rbyd_lookup(&lfs3, &rbyd, rid, LFS3_TAG_DATA, &data); if (tag >= 0) { lfs3_ssize_t size = lfs3_data_read(&lfs3, &data, buffer, 4); printf("%.*s", size, buffer); } else { printf("?"); } for (uint8_t u = 0; u < M; u++) { tag = lfs3_rbyd_lookup(&lfs3, &rbyd, rid, LFS3_TAG_ATTR(u), &data); if (tag >= 0) { lfs3_ssize_t size = lfs3_data_read(&lfs3, &data, buffer, 4); printf("%.*s", size, buffer); } else { printf("_"); } } if (rid < (lfs3_ssize_t)count-1) { printf(", "); } } printf("]\n"); assert(count == rbyd.weight); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)count; rid++) { lfs3_rbyd_lookup(&lfs3, &rbyd, rid, LFS3_TAG_DATA, &data) => LFS3_TAG_DATA; lfs3_data_read(&lfs3, &data, buffer, 4) => 1; assert(memcmp(&sim[rid*(M+1)], buffer, 1) == 0); } // cleanup free(sim); ''' [cases.test_rbyd_fuzz_sparse] defines.N = 'range(1, 33)' defines.W = 5 defines.SEED = 'range(1000)' fuzz = 'SEED' # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; lfs3_stag_t tag_; lfs3_ssize_t rid_; lfs3_size_t weight_; lfs3_data_t data_; lfs3_data_t data; uint8_t buffer[4]; printf("perm: ["); uint32_t prng = SEED; lfs3_size_t count = 0; for (unsigned i = 0; i < N; i++) { // choose create/delete/grow/shrink uint8_t op = TEST_PRNG(&prng) % 4; // choose an rid lfs3_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose a weight lfs3_size_t weight = 1 + (TEST_PRNG(&prng) % W); if (rid == (lfs3_ssize_t)count || op == 0) { printf("c%dw%d=%c", rid, weight, 'a'+(i % 26)); count += 1; } else if (op == 1) { printf("d%d", rid); count -= 1; } else if (op == 2) { printf("g%dw%d", rid, weight); } else if (op == 3) { printf("s%dw%d", rid, weight); } if (i < N-1) { printf(", "); } } printf("]\n"); // set up a simulation to compare against, fun fact this performs // worst than our actual rbyd block! char *sim = malloc(N); lfs3_size_t *sim_weights = malloc(N*sizeof(lfs3_size_t)); memset(sim, 0, N); memset(sim_weights, 0, N*sizeof(lfs3_size_t)); // set up rbyd block rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; prng = SEED; count = 0; for (unsigned i = 0; i < N; i++) { // choose create/delete/grow/shrink uint8_t op = TEST_PRNG(&prng) % 4; // choose an rid lfs3_ssize_t rid = TEST_PRNG(&prng) % (count+1); // choose a weight lfs3_size_t weight = 1 + (TEST_PRNG(&prng) % W); // calculate actual rid in rbyd space lfs3_ssize_t weighted_rid = 0; for (lfs3_ssize_t j = 0; j < rid; j++) { weighted_rid += sim_weights[j]; } if (rid == (lfs3_ssize_t)count || op == 0) { // update our sim memmove(sim+rid+1, sim+rid, count-rid); memmove(sim_weights+rid+1, sim_weights+rid, (count-rid)*sizeof(lfs3_size_t)); sim[rid] = 'a'+(i % 26); sim_weights[rid] = weight; count += 1; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, weighted_rid, LFS3_RATTRS( LFS3_RATTR(3, LFS3_TAG_DATA, -2, LFS3_FROM_BUF, 1), LFS3_RATTR_WEIGHT(+weight), LFS3_RATTR_ARG(&(uint8_t){'a'+(i % 26)}), LFS3_RATTR_NULL)) => 0; } else if (op == 1) { // get the correct weight from the sim weight_ = sim_weights[rid]; // update our sim memmove(sim+rid, sim+rid+1, count-rid-1); memmove(sim_weights+rid, sim_weights+rid+1, (count-rid-1)*sizeof(lfs3_size_t)); count -= 1; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, weighted_rid+weight_-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_RM, -2), LFS3_RATTR_WEIGHT(-weight_), LFS3_RATTR_NULL)) => 0; } else if (op == 2) { // get the correct weight from the sim weight_ = sim_weights[rid]; // update our sim sim_weights[rid] += weight; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, weighted_rid+weight_-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(+weight), LFS3_RATTR_NULL)) => 0; } else if (op == 3) { // get the correct weight from the sim weight_ = sim_weights[rid]; // don't let shrink go to zero here! this is already hard enough // to simulate weight = lfs3_min(weight, weight_-1); // update our sim sim_weights[rid] -= weight; // update our rbyd lfs3_rbyd_commit(&lfs3, &rbyd, weighted_rid+weight_-1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_GROW, -2), LFS3_RATTR_WEIGHT(-weight), LFS3_RATTR_NULL)) => 0; } } // compare rbyd vs simulation printf("expd: ["); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)count; rid++) { printf("%cw%d", sim[rid], sim_weights[rid]); if (rid < (lfs3_ssize_t)count-1) { printf(", "); } } printf("]\n"); printf("rbyd: ["); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)count; rid++) { // calculate actual rid in rbyd space lfs3_ssize_t weighted_rid = 0; for (lfs3_ssize_t j = 0; j < rid; j++) { weighted_rid += sim_weights[j]; } tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, weighted_rid, LFS3_TAG_DATA, &rid_, &weight_, &data_); if (tag_ >= 0) { lfs3_ssize_t size = lfs3_data_read(&lfs3, &data_, buffer, 4); if (size >= 0) { printf("%.*sw%d", size, buffer, weight_); } else { printf("?"); } } else { printf("?"); } if (rid < (lfs3_ssize_t)count-1) { printf(", "); } } printf("]\n"); // calculate total weight lfs3_size_t total_weight = 0; for (lfs3_ssize_t j = 0; j < (lfs3_ssize_t)count; j++) { total_weight += sim_weights[j]; } assert(total_weight == rbyd.weight); for (lfs3_ssize_t rid = 0; rid < (lfs3_ssize_t)count; rid++) { // calculate actual rid in rbyd space lfs3_ssize_t weighted_rid = 0; for (lfs3_ssize_t j = 0; j < rid; j++) { weighted_rid += sim_weights[j]; } tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, weighted_rid, LFS3_TAG_DATA, &rid_, &weight_, &data_); assert(tag_ >= 0); lfs3_rbyd_lookup(&lfs3, &rbyd, rid_, tag_, &data) => tag_; lfs3_data_read(&lfs3, &data, buffer, 4) => 1; assert(memcmp(&sim[rid], buffer, 1) == 0); } // cleanup free(sim); free(sim_weights); ''' ### Supertype/subtype-wide things ### # subtype-wide [cases.test_rbyd_subwide_lookup_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // build the attribute list for the current permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // test that we can lookup each rattr with a wide lookup lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_stag_t tag_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); assert(tag_ == LFS3_TAG_ATTR((j + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 2); } } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_subwide_remove_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { // print what we are removing to help debugging printf("--- remove: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // remove with a wide tag lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_tag_MASK8 | LFS3_TAG_ATTR, 0), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); if (k != j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { if (k == j) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_) => LFS3_ERR_NOENT; } else { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 2); } } } // cleanup free(backup_block); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_subwide_replace_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try replacing each tag for (unsigned j = 0; j < N; j++) { // print what we are replacing to help debugging printf("--- replace: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // replace with bitwise inverse lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_MASK8 | LFS3_TAG_ATTR(~(j + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 3), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); if (k == j) { assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 3); } else { assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); if (k == j) { assert(tag_ == LFS3_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 3); } else { assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 2); } } } // cleanup free(backup_block); } ''' [cases.test_rbyd_subwide_mixed_lookup_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // build the attribute list for the current permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(0x80), 0, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // test that we can lookup each rattr with a wide lookup lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_stag_t tag_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); assert(tag_ == LFS3_TAG_ATTR(0x7f & (j + SHIFT))); assert(lfs3_data_size(data_) == 2); } } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_subwide_mixed_remove_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(0x80), 0, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { // print what we are removing to help debugging printf("--- remove: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // remove with a wide tag lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_tag_MASK8 | LFS3_TAG_ATTR, 0), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); if (k != j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(0x7f & (k + SHIFT))); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(0x80)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 1); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { if (k == j) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_) => LFS3_ERR_NOENT; } else { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 2); } } } // cleanup free(backup_block); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_subwide_mixed_replace_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR(0x80), 0, LFS3_FROM_BUF, 1), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try replacing each tag for (unsigned j = 0; j < N; j++) { // print what we are replacing to help debugging printf("--- replace: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // replace with bitwise inverse lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_MASK8 | LFS3_TAG_ATTR(~(j + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 3), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); if (k == j) { assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(0x7f & ~(k + SHIFT))); assert(weight_ == 0); assert(lfs3_data_size(data_) == 3); } else { assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(0x7f & (k + SHIFT))); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(0x80)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 1); } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); if (k == j) { assert(tag_ == LFS3_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 3); } else { assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 2); } } } // cleanup free(backup_block); } ''' [cases.test_rbyd_subwide_weighted_lookup_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // build the attribute list for the current permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // test that we can lookup each rattr with a wide lookup lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_stag_t tag_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); assert(tag_ == LFS3_TAG_ATTR((j + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 4); } } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_subwide_weighted_remove_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { // print what we are removing to help debugging printf("--- remove: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // remove with a wide tag lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_tag_MASK8 | LFS3_TAG_ATTR, 0), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N-1; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); if (k == j) { assert(rid_ == k+1); assert(tag_ == LFS3_TAG_ATTR((k+1 + SHIFT) & 0x7f)); assert(weight_ == 2); assert(lfs3_data_size(data_) == 4); } else if (k > j) { assert(rid_ == k+1); assert(tag_ == LFS3_TAG_ATTR((k+1 + SHIFT) & 0x7f)); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); } else { assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { if (k == j) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_) => LFS3_ERR_NOENT; } else { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 4); } } } // cleanup free(backup_block); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_subwide_weighted_replace_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try replacing each tag for (unsigned j = 0; j < N; j++) { // print what we are replacing to help debugging printf("--- replace: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // replace with bitwise inverse lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_MASK8 | LFS3_TAG_ATTR(~(j + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 6), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); if (k == j) { assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(weight_ == 1); assert(lfs3_data_size(data_) == 6); } else { assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); if (k == j) { assert(tag_ == LFS3_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 6); } else { assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 4); } } } // cleanup free(backup_block); } ''' # supertype-wide [cases.test_rbyd_supwide_lookup_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // build the attribute list for the current permutation rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // a supwide rattr lookup only gets the file type lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], 0) => 0; assert(rbyd.weight == N); for (unsigned j = 0; j < N; j++) { lfs3_stag_t tag_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, j, LFS3_tag_MASK12, &data_); assert(tag_ == LFS3_TAG_DATA); assert(lfs3_data_size(data_) == 4); } } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_supwide_remove_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { // print what we are removing to help debugging printf("--- remove: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // remove with a wide tag lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_tag_MASK12 | LFS3_TAG_ATTR, 0), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N; k++) { if (k != j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == ((k == j+1) ? 2 : 1)); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { if (k == j) { lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_) => LFS3_ERR_NOENT; } else { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 2); } } } // cleanup free(backup_block); } ''' # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_supwide_replace_permutations] defines.N = 'range(1, 7)' defines.SHIFT = [0, 3, -3] # PERMUTATION=-1 => exhaust all permutations # PERMUTATION=n => reproduce a specific permutation defines.PERMUTATION = -1 # large progs take too long for now if = 'PROG_SIZE < 512' in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; const uint8_t names[6][6] = { "\xaa\xaa\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee\xee\xee", "\xff\xff\xff\xff\xff\xff", }; // test all permutations of a given size size_t perm_count = TEST_FACTORIAL(N); for (size_t i = 0; i < ((PERMUTATION == -1) ? perm_count : 1); i++) { uint32_t perm[N]; size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION; TEST_PERMUTATION(perm_i, perm, N); // print permutation to help debugging printf("--- permutation: %zd [", perm_i); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; for (unsigned j = 0; j < N; j++) { // adjust rid based on future insertions uint16_t rid = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { rid -= 1; } } // give each rattr a subtype based on its rid + SHIFT lfs3_rbyd_commit(&lfs3, &rbyd, rid, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR(2, LFS3_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 2), LFS3_RATTR_ARG(names[perm[j] % 6]), LFS3_RATTR_NULL)) => 0; } assert(rbyd.weight == N); // copy block so we can reset after each remove lfs3_rbyd_t backup_rbyd = rbyd; uint8_t *backup_block = malloc(lfs3_rbyd_eoff(&rbyd)); CFG->read(CFG, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd)) => 0; // try replacing each tag for (unsigned j = 0; j < N; j++) { // print what we are replacing to help debugging printf("--- replace: %d ---\n", j); rbyd = backup_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_bd_prog(&lfs3, rbyd.blocks[0], 0, backup_block, lfs3_rbyd_eoff(&rbyd), NULL) => 0; lfs3_bd_flush(&lfs3, NULL) => 0; // replace with bitwise inverse lfs3_rbyd_commit(&lfs3, &rbyd, j, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_MASK12 | LFS3_TAG_ATTR(~(j + SHIFT) & 0x7f), 0, LFS3_FROM_BUF, 3), LFS3_RATTR_ARG(names[j % 6]), LFS3_RATTR_NULL)) => 0; // try traversing over the tags lfs3_rbyd_fetch(&lfs3, &rbyd, rbyd.blocks[0], CFG->block_size) => 0; lfs3_tag_t tag_ = 0; lfs3_ssize_t rid_ = -1; lfs3_size_t weight_; lfs3_data_t data_; for (unsigned k = 0; k < N; k++) { if (k == j) { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(weight_ == 1); assert(lfs3_data_size(data_) == 3); } else { tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_); assert(rid_ == k); assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 2); } } lfs3_rbyd_lookupnext(&lfs3, &rbyd, rid_, tag_+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; // also test that we can lookup each tag with a wide lookup for (unsigned k = 0; k < N; k++) { tag_ = lfs3_rbyd_lookup(&lfs3, &rbyd, k, LFS3_tag_MASK8 | LFS3_TAG_ATTR, &data_); if (k == j) { assert(tag_ == LFS3_TAG_ATTR(~(k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 3); } else { assert(tag_ == LFS3_TAG_ATTR((k + SHIFT) & 0x7f)); assert(lfs3_data_size(data_) == 2); } } } // cleanup free(backup_block); } ''' # Some very specific cases we want to cover # One downside of having only altgt tags (not altge) is that we can end # up with an awkward null tag in our rbyd. Need to test we handle this # correctly. [cases.test_rbyd_unreachable_hole] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // create a null tag hole rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(0), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(0), 0), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); // can we still access things? lfs3_ssize_t rid_; lfs3_stag_t tag_; lfs3_size_t weight_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(rid_ == -1); assert(tag_ == LFS3_TAG_ATTR(1)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 4); uint8_t rbuf[32]; lfs3_data_read(&lfs3, &data_, rbuf, 32) => 4; assert(memcmp(rbuf, "\xbb\xbb\xbb\xbb", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(1)+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_unreachable_hole_rm] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // create a null tag hole rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(0), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(0), 0), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); // remove a neighbor to the hole lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(1), 0), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); // can we still access things? lfs3_ssize_t rid_; lfs3_stag_t tag_; lfs3_size_t weight_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(rid_ == -1); assert(tag_ == LFS3_TAG_ATTR(2)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 4); uint8_t rbuf[32]; lfs3_data_read(&lfs3, &data_, rbuf, 32) => 4; assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2)+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_unreachable_hole_delete] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // create a null tag hole rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(0), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(0), 0), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 2); // delete a neighbor to the hole lfs3_rbyd_commit(&lfs3, &rbyd, 0, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM, -1), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); // can we still access things? lfs3_ssize_t rid_; lfs3_stag_t tag_; lfs3_size_t weight_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(rid_ == 0); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); uint8_t rbuf[32]; lfs3_data_read(&lfs3, &data_, rbuf, 32) => 4; assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_unreachable_hole_subwide] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // create a null tag hole rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(0x00), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(0x01), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_ATTR(0x80), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(0), 0), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); // subwide replace a neighbor to the hole lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_MASK8 | LFS3_TAG_ATTR(0x02), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 0); // can we still access things? lfs3_ssize_t rid_; lfs3_stag_t tag_; lfs3_size_t weight_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(rid_ == -1); assert(tag_ == LFS3_TAG_ATTR(0x02)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 4); uint8_t rbuf[32]; lfs3_data_read(&lfs3, &data_, rbuf, 32) => 4; assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2)+1, &rid_, &weight_, &data_); assert(rid_ == -1); assert(tag_ == LFS3_TAG_ATTR(0x80)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 4); lfs3_data_read(&lfs3, &data_, rbuf, 32) => 4; assert(memcmp(rbuf, "\xdd\xdd\xdd\xdd", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(0x80)+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; ''' [cases.test_rbyd_unreachable_hole_supwide] in = 'lfs3.c' code = ''' lfs3_t lfs3; lfs3_init(&lfs3, LFS3_M_RDWR, CFG) => 0; lfs3_rbyd_t init_rbyd = { .blocks[0] = 0, .eoff = 0, .cksum = 0, .trunk = 0, .weight = 0, }; lfs3_rbyd_t rbyd; // create a null tag hole rbyd = init_rbyd; lfs3_bd_erase(&lfs3, rbyd.blocks[0]) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_TAG_ATTR(0), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xaa\xaa\xaa\xaa"), LFS3_RATTR(2, LFS3_TAG_ATTR(1), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xbb\xbb\xbb\xbb"), LFS3_RATTR(2, LFS3_TAG_DATA, +1, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xdd\xdd\xdd\xdd"), LFS3_RATTR_NULL)) => 0; lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(1, LFS3_tag_RM | LFS3_TAG_ATTR(0), 0), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); // supwide replace a neighbor to the hole lfs3_rbyd_commit(&lfs3, &rbyd, -1, LFS3_RATTRS( LFS3_RATTR(2, LFS3_tag_MASK12 | LFS3_TAG_ATTR(2), 0, LFS3_FROM_BUF, 4), LFS3_RATTR_ARG("\xcc\xcc\xcc\xcc"), LFS3_RATTR_NULL)) => 0; assert(rbyd.weight == 1); // can we still access things? lfs3_ssize_t rid_; lfs3_stag_t tag_; lfs3_size_t weight_; lfs3_data_t data_; tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, 0, &rid_, &weight_, &data_); assert(rid_ == -1); assert(tag_ == LFS3_TAG_ATTR(2)); assert(weight_ == 0); assert(lfs3_data_size(data_) == 4); uint8_t rbuf[32]; lfs3_data_read(&lfs3, &data_, rbuf, 32) => 4; assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0); tag_ = lfs3_rbyd_lookupnext(&lfs3, &rbyd, -1, LFS3_TAG_ATTR(2)+1, &rid_, &weight_, &data_); assert(rid_ == 0); assert(tag_ == LFS3_TAG_DATA); assert(weight_ == 1); assert(lfs3_data_size(data_) == 4); lfs3_data_read(&lfs3, &data_, rbuf, 32) => 4; assert(memcmp(rbuf, "\xdd\xdd\xdd\xdd", 4) == 0); lfs3_rbyd_lookupnext(&lfs3, &rbyd, 0, LFS3_TAG_DATA+1, &rid_, &weight_, &data_) => LFS3_ERR_NOENT; '''