More post-stress-test fixes

- Prevent _split types of new blocks
- Stop updating new blocks only after the whole update, otherwise pointers
  may become invalid
- Use recheck_none for updates initially
- Use UINT64_MAX as initial block version when postponing ops, otherwise the
  check fails when the block is initially empty. This for example leads to
  writing both leaf items & block pointers (which is incorrect) into the root
  block when starting stress-test with --parallelism 32
- Fix -EINTR comparison
antietcd
Vitaliy Filippov 2023-10-15 02:37:02 +03:00
parent babaf2a0ce
commit 36f4717d0d
1 changed files with 17 additions and 10 deletions

View File

@ -792,7 +792,7 @@ void kv_op_t::exec()
cur_level = -db->base_block_level; cur_level = -db->base_block_level;
path.clear(); path.clear();
path.push_back(0); path.push_back(0);
recheck_policy = (opcode == KV_GET_CACHED ? KV_RECHECK_NONE : KV_RECHECK_LEAF); recheck_policy = (opcode == KV_GET ? KV_RECHECK_LEAF : KV_RECHECK_NONE);
if (opcode == KV_GET || opcode == KV_GET_CACHED) if (opcode == KV_GET || opcode == KV_GET_CACHED)
get(); get();
else if (opcode == KV_SET || opcode == KV_DEL) else if (opcode == KV_SET || opcode == KV_DEL)
@ -1037,7 +1037,7 @@ static kv_block_t *create_new_block(kv_db_t *db, kv_block_t *old_blk, const std:
auto blk = &db->block_cache[new_offset]; auto blk = &db->block_cache[new_offset];
blk->usage = db->usage_counter; blk->usage = db->usage_counter;
blk->level = old_blk->level; blk->level = old_blk->level;
blk->type = old_blk->type; blk->type = old_blk->type == KV_LEAF_SPLIT || old_blk->type == KV_LEAF ? KV_LEAF : KV_INT;
blk->offset = new_offset; blk->offset = new_offset;
blk->updating = true; blk->updating = true;
blk->key_ge = right ? separator : old_blk->key_ge; blk->key_ge = right ? separator : old_blk->key_ge;
@ -1207,7 +1207,7 @@ void kv_op_t::update_find()
} }
else else
{ {
update_block(path.size()-1, opcode == KV_DEL, key, value, 0, [=](int res) update_block(path.size()-1, opcode == KV_DEL, key, value, UINT64_MAX, [=](int res)
{ {
finish(res); finish(res);
}); });
@ -1265,7 +1265,7 @@ void kv_op_t::resume_split()
auto blk = &db->block_cache.at(cur_block); auto blk = &db->block_cache.at(cur_block);
update_block( update_block(
path.size()-2, false, blk->right_half, path.size()-2, false, blk->right_half,
std::string((char*)&blk->right_half_block, sizeof(blk->right_half_block)), 0, std::string((char*)&blk->right_half_block, sizeof(blk->right_half_block)), UINT64_MAX,
[=](int res) [=](int res)
{ {
if (res < 0) if (res < 0)
@ -1278,7 +1278,8 @@ void kv_op_t::resume_split()
); );
} }
void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key, const std::string & value, uint64_t block_ver, std::function<void(int)> cb) void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key,
const std::string & value, uint64_t block_ver, std::function<void(int)> cb)
{ {
auto blk_it = db->block_cache.find(path[path_pos]); auto blk_it = db->block_cache.find(path[path_pos]);
if (blk_it == db->block_cache.end()) if (blk_it == db->block_cache.end())
@ -1289,7 +1290,7 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
return; return;
} }
auto blk = &blk_it->second; auto blk = &blk_it->second;
if (block_ver == 0) if (block_ver == UINT64_MAX)
{ {
block_ver = db->known_versions[blk->offset/db->ino_block_size]; block_ver = db->known_versions[blk->offset/db->ino_block_size];
} }
@ -1364,7 +1365,7 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
else else
blk->apply_change(); blk->apply_change();
db->stop_updating(blk); db->stop_updating(blk);
if (res == EINTR) if (res == -EINTR)
{ {
update(); update();
} }
@ -1387,10 +1388,10 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
auto orig_right_blk = create_new_block(db, blk, separator, key, value, true); auto orig_right_blk = create_new_block(db, blk, separator, key, value, true);
write_new_block(db, orig_right_blk, [=](int res, kv_block_t *right_blk) write_new_block(db, orig_right_blk, [=](int res, kv_block_t *right_blk)
{ {
db->stop_updating(right_blk);
if (res < 0) if (res < 0)
{ {
blk->cancel_change(); blk->cancel_change();
db->stop_updating(right_blk);
db->stop_updating(blk); db->stop_updating(blk);
cb(res); cb(res);
return; return;
@ -1402,10 +1403,10 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
auto orig_left_blk = create_new_block(db, blk, separator, key, value, false); auto orig_left_blk = create_new_block(db, blk, separator, key, value, false);
write_new_block(db, orig_left_blk, [=](int res, kv_block_t *left_blk) write_new_block(db, orig_left_blk, [=](int res, kv_block_t *left_blk)
{ {
db->stop_updating(left_blk);
if (res < 0) if (res < 0)
{ {
blk->cancel_change(); blk->cancel_change();
db->stop_updating(left_blk);
db->stop_updating(blk); db->stop_updating(blk);
cb(res); cb(res);
return; return;
@ -1429,10 +1430,12 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
db->stop_updating(blk); db->stop_updating(blk);
clear_block(db, left_blk, 0, [=, left_offset = left_blk->offset](int res) clear_block(db, left_blk, 0, [=, left_offset = left_blk->offset](int res)
{ {
db->stop_updating(left_blk);
if (res < 0) if (res < 0)
fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", left_offset, strerror(-res), res); fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", left_offset, strerror(-res), res);
clear_block(db, right_blk, 0, [=, right_offset = right_blk->offset](int res) clear_block(db, right_blk, 0, [=, right_offset = right_blk->offset](int res)
{ {
db->stop_updating(right_blk);
if (res < 0) if (res < 0)
fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", right_offset, strerror(-res), res); fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", right_offset, strerror(-res), res);
// CAS failure - zero garbage left_blk and right_blk and retry from the beginning // CAS failure - zero garbage left_blk and right_blk and retry from the beginning
@ -1447,6 +1450,8 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
{ {
std::swap(db->block_cache[0], *new_root); std::swap(db->block_cache[0], *new_root);
db->base_block_level = -new_root->level; db->base_block_level = -new_root->level;
db->stop_updating(left_blk);
db->stop_updating(right_blk);
db->stop_updating(&db->block_cache[0]); db->stop_updating(&db->block_cache[0]);
cb(0); cb(0);
} }
@ -1484,6 +1489,7 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
{ {
clear_block(db, right_blk, 0, [=, right_offset = right_blk->offset](int res) clear_block(db, right_blk, 0, [=, right_offset = right_blk->offset](int res)
{ {
db->stop_updating(right_blk);
if (res < 0) if (res < 0)
fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", right_offset, strerror(-res), res); fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", right_offset, strerror(-res), res);
// CAS failure - zero garbage right_blk and retry from the beginning // CAS failure - zero garbage right_blk and retry from the beginning
@ -1495,11 +1501,12 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
} }
else else
{ {
db->stop_updating(right_blk);
// Add a reference to the parent block // Add a reference to the parent block
// Do not cleanup anything on failure because stored right_blk is already referenced // Do not cleanup anything on failure because stored right_blk is already referenced
update_block( update_block(
path_pos-1, false, separator, path_pos-1, false, separator,
std::string((char*)&right_blk->offset, sizeof(right_blk->offset)), 0, std::string((char*)&right_blk->offset, sizeof(right_blk->offset)), UINT64_MAX,
cb cb
); );
} }