#include <stdint.h>
#include "out.h"
#include "libpmempool.h"
#include "pmempool.h"
#include "pool.h"
#include "check.h"
#include "check_util.h"
#define CHECK_RESULT_IS_STOP(result)\
((result) == CHECK_RESULT_ERROR ||\
(result) == CHECK_RESULT_INTERNAL_ERROR ||\
((result) == CHECK_RESULT_CANNOT_REPAIR) ||\
((result) == CHECK_RESULT_NOT_CONSISTENT))
struct step {
void (*func)(PMEMpoolcheck *);
enum pool_type type;
bool part;
};
static const struct step steps[] = {
{
.type = POOL_TYPE_ANY,
.func = check_backup,
.part = true,
},
{
.type = POOL_TYPE_BLK | POOL_TYPE_LOG |
POOL_TYPE_OBJ | POOL_TYPE_CTO |
POOL_TYPE_UNKNOWN,
.func = check_pool_hdr,
.part = true,
},
{
.type = POOL_TYPE_BLK | POOL_TYPE_LOG |
POOL_TYPE_OBJ | POOL_TYPE_CTO |
POOL_TYPE_UNKNOWN,
.func = check_pool_hdr_uuids,
.part = true,
},
{
.type = POOL_TYPE_LOG,
.func = check_log,
.part = false,
},
{
.type = POOL_TYPE_BLK,
.func = check_blk,
.part = false,
},
{
.type = POOL_TYPE_CTO,
.func = check_cto,
.part = false,
},
{
.type = POOL_TYPE_BLK | POOL_TYPE_BTT,
.func = check_btt_info,
.part = false,
},
{
.type = POOL_TYPE_BLK | POOL_TYPE_BTT,
.func = check_btt_map_flog,
.part = false,
},
{
.type = POOL_TYPE_BLK | POOL_TYPE_LOG |
POOL_TYPE_BTT | POOL_TYPE_CTO,
.func = check_write,
.part = false,
},
{
.func = NULL,
},
};
int
check_init(PMEMpoolcheck *ppc)
{
LOG(3, NULL);
if (!(ppc->data = check_data_alloc()))
goto error_data_malloc;
if (!(ppc->pool = pool_data_alloc(ppc)))
goto error_pool_malloc;
return 0;
error_pool_malloc:
check_data_free(ppc->data);
error_data_malloc:
return -1;
}
#ifdef _WIN32
void
convert_status_cache(PMEMpoolcheck *ppc, char *buf, size_t size)
{
cache_to_utf8(ppc->data, buf, size);
}
#endif
static struct check_status *
status_get(PMEMpoolcheck *ppc)
{
struct check_status *status = NULL;
check_clear_status_cache(ppc->data);
if ((status = check_pop_info(ppc->data)))
return status;
if ((status = check_pop_error(ppc->data)))
return status;
if (ppc->result == CHECK_RESULT_ASK_QUESTIONS) {
if (check_push_answer(ppc))
if ((status = check_pop_info(ppc->data)))
return status;
if ((status = check_pop_question(ppc->data)))
return status;
ppc->result = CHECK_RESULT_PROCESS_ANSWERS;
} else if (CHECK_RESULT_IS_STOP(ppc->result))
check_end(ppc->data);
return NULL;
}
struct check_status *
check_step(PMEMpoolcheck *ppc)
{
LOG(3, NULL);
struct check_status *status = NULL;
if ((status = status_get(ppc)) || check_is_end(ppc->data))
return status;
const struct step *step = &steps[check_step_get(ppc->data)];
if (step->func == NULL) {
check_end(ppc->data);
return status;
}
if (!(step->type & ppc->pool->params.type) ||
(ppc->pool->params.is_part && !step->part)) {
check_step_inc(ppc->data);
return NULL;
}
step->func(ppc);
if (ppc->result != CHECK_RESULT_ASK_QUESTIONS)
check_step_inc(ppc->data);
return status_get(ppc);
}
void
check_fini(PMEMpoolcheck *ppc)
{
LOG(3, NULL);
pool_data_free(ppc->pool);
check_data_free(ppc->data);
}
int
check_is_end(struct check_data *data)
{
return check_is_end_util(data);
}
struct pmempool_check_status *
check_status_get(struct check_status *status)
{
return check_status_get_util(status);
}