93 lines
2.9 KiB
C++
93 lines
2.9 KiB
C++
// Copyright (c) Vitaliy Filippov, 2019+
|
|
// License: VNPL-1.1 (see README.md for details)
|
|
|
|
#include "blockstore_impl.h"
|
|
#include "blockstore_internal.h"
|
|
|
|
// Handles both stabilize (commit) and rollback
|
|
int blockstore_impl_t::dequeue_stable(blockstore_op_t *op)
|
|
{
|
|
obj_ver_id *v = (obj_ver_id*)op->buf;
|
|
auto priv = PRIV(op);
|
|
if (priv->op_state == 1) goto resume_1;
|
|
else if (priv->op_state == 2) goto resume_2;
|
|
else if (priv->op_state == 3) goto resume_3;
|
|
else if (priv->op_state == 4) goto resume_4;
|
|
else if (priv->op_state == 5) goto resume_5;
|
|
assert(!priv->op_state);
|
|
op->retval = 0;
|
|
priv->modified_block = priv->modified_block2 = UINT32_MAX;
|
|
for (priv->stab_pos = 0; priv->stab_pos < op->len; priv->stab_pos++)
|
|
{
|
|
{
|
|
auto obj = heap->read_entry(v[priv->stab_pos].oid);
|
|
if (!obj)
|
|
{
|
|
op->retval = -ENOENT;
|
|
FINISH_OP(op);
|
|
return 2;
|
|
}
|
|
int res = op->opcode == BS_OP_STABLE
|
|
? heap->add_commit(obj, v[priv->stab_pos].version, &priv->modified_block2)
|
|
: heap->add_rollback(obj, v[priv->stab_pos].version, &priv->modified_block2);
|
|
if (res == EBUSY)
|
|
{
|
|
op->retval = -EBUSY;
|
|
FINISH_OP(op);
|
|
return 2;
|
|
}
|
|
if (res == ENOSPC)
|
|
{
|
|
if (!heap->get_to_compact_count())
|
|
{
|
|
// no space
|
|
op->retval = -ENOSPC;
|
|
FINISH_OP(op);
|
|
return 2;
|
|
}
|
|
if (priv->modified_block2 != UINT32_MAX)
|
|
{
|
|
priv->stab_pos--;
|
|
goto resume_1;
|
|
}
|
|
priv->wait_for = WAIT_COMPACTION;
|
|
priv->wait_detail = heap->get_compacted_count();
|
|
flusher->request_trim();
|
|
return 0;
|
|
}
|
|
assert(res == 0);
|
|
}
|
|
resume_1:
|
|
if (priv->modified_block != UINT32_MAX && priv->modified_block2 != priv->modified_block)
|
|
{
|
|
BS_SUBMIT_CHECK_SQES(1);
|
|
prepare_meta_block_write(priv->modified_block);
|
|
resume_2:
|
|
if (meta_block_is_pending(priv->modified_block))
|
|
{
|
|
priv->op_state = 2;
|
|
return 1;
|
|
}
|
|
}
|
|
priv->modified_block = priv->modified_block2;
|
|
if (priv->stab_pos == op->len-1 && priv->modified_block2 != UINT32_MAX)
|
|
{
|
|
priv->modified_block2 = UINT32_MAX;
|
|
goto resume_1;
|
|
}
|
|
}
|
|
// Fsync, just because our semantics imply that commit (stabilize) is immediately fsynced
|
|
priv->op_state = 3;
|
|
resume_3:
|
|
resume_4:
|
|
resume_5:
|
|
int res = do_sync(op, 3);
|
|
if (res != 2)
|
|
{
|
|
return res;
|
|
}
|
|
// Done. Don't touch op->retval - if anything resulted in ENOENT, return it as is
|
|
FINISH_OP(op);
|
|
return 2;
|
|
}
|