Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 57 additions & 31 deletions src/common/btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ struct btr_context {
static int
btr_class_init(umem_off_t root_off, struct btr_root *root, unsigned int tree_class,
uint64_t *tree_feats, struct umem_attr *uma, daos_handle_t coh, void *priv,
btr_report_fn_t report_fn, void *report_arg, struct btr_instance *tins);
report_fn_t report_fn, void *report_arg, struct btr_instance *tins);
static struct btr_record *btr_node_rec_at(struct btr_context *tcx,
umem_off_t nd_off,
unsigned int at);
Expand Down Expand Up @@ -318,11 +318,6 @@ btr_ops(struct btr_context *tcx)
return tcx->tc_tins.ti_ops;
}

static inline void
report_fn_nop(void *arg, enum btr_report_type type, const char *fmt, ...)
{
}

/**
* Create a btree context (in volatile memory).
*
Expand Down Expand Up @@ -4596,7 +4591,7 @@ btr_class_feats_init(unsigned int tree_class, uint64_t *tree_feats, struct btr_c
static int
btr_class_init(umem_off_t root_off, struct btr_root *root, unsigned int tree_class,
uint64_t *tree_feats, struct umem_attr *uma, daos_handle_t coh, void *priv,
btr_report_fn_t report_fn, void *report_arg, struct btr_instance *tins)
report_fn_t report_fn, void *report_arg, struct btr_instance *tins)
{
struct btr_class *tc;
int rc;
Expand Down Expand Up @@ -4624,29 +4619,28 @@ btr_class_init(umem_off_t root_off, struct btr_root *root, unsigned int tree_cla

/* XXX should be multi-thread safe */
if (tree_class >= BTR_TYPE_MAX || DAOS_FAIL_CHECK(DAOS_FAULT_BTREE_OPEN_INV_CLASS)) {
report_fn(report_arg, BTR_REPORT_ERROR, TREE_CLASS_STR INVALID_CLASS_FMT,
tree_class);
report_fn(report_arg, REPORT_ERROR, TREE_CLASS_STR INVALID_CLASS_FMT, tree_class);
D_DEBUG(DB_TRACE, INVALID_CLASS_FMT, tree_class);
return -DER_INVAL;
}

tc = &btr_class_registered[tree_class];
if (tc->tc_ops == NULL || DAOS_FAIL_CHECK(DAOS_FAULT_BTREE_OPEN_UNREG_CLASS)) {
report_fn(report_arg, BTR_REPORT_ERROR, TREE_CLASS_STR UNREGISTERED_CLASS_FMT,
report_fn(report_arg, REPORT_ERROR, TREE_CLASS_STR UNREGISTERED_CLASS_FMT,
tree_class);
D_DEBUG(DB_TRACE, UNREGISTERED_CLASS_FMT, tree_class);
return -DER_NONEXIST;
}
report_fn(report_arg, BTR_REPORT_MSG, TREE_CLASS_STR OK_STR);
report_fn(report_arg, REPORT_MSG, TREE_CLASS_STR OK_STR);

rc = btr_class_feats_init(tree_class, tree_feats, tc);
if (rc != DER_SUCCESS) {
report_fn(report_arg, BTR_REPORT_ERROR, TREE_FEATURES_STR UNSUPPORTED_FEATURES_FMT,
report_fn(report_arg, REPORT_ERROR, TREE_FEATURES_STR UNSUPPORTED_FEATURES_FMT,
*tree_feats, tc->tc_feats);
D_ERROR(UNSUPPORTED_FEATURES_FMT, *tree_feats, tc->tc_feats);
return rc;
}
report_fn(report_arg, BTR_REPORT_MSG, TREE_FEATURES_STR OK_STR);
report_fn(report_arg, REPORT_MSG, TREE_FEATURES_STR OK_STR);

tins->ti_ops = tc->tc_ops;
return rc;
Expand Down Expand Up @@ -4761,6 +4755,17 @@ dbtree_overhead_get(int alloc_overhead, unsigned int tclass, uint64_t otype,
return 0;
}

static int
btr_rec_check(struct btr_context *tcx, struct btr_record *rec, report_fn_t report_fn,
void *report_arg)
{
if (!btr_ops(tcx)->to_rec_check) {
return -DER_NOSYS;
}

return btr_ops(tcx)->to_rec_check(&tcx->tc_tins, rec, report_fn, report_arg);
}

#define CK_BTREE_NODE_FMT "Node (off=%#lx)... "
#define CK_BTREE_NODE_MALFORMED_STR "malformed - "
#define CK_BTREE_NON_ZERO_PADDING_FMT CK_BTREE_NODE_MALFORMED_STR "tn_pad_32 != 0 (%#" PRIx32 ")"
Expand All @@ -4771,13 +4776,14 @@ dbtree_overhead_get(int alloc_overhead, unsigned int tclass, uint64_t otype,
*
* \param[in] nd Node to check.
* \param[in] nd_off Node's offset.
* \param[in] ck Checker.
* \param[in] report_fn Report function.
* \param[in] report_arg Argument for the report function.
*
* \retval DER_SUCCESS The node is correct.
* \retval -DER_NOTYPE The node is malformed.
*/
static int
btr_node_check(struct btr_node *nd, umem_off_t nd_off, btr_report_fn_t report_fn, void *report_arg,
btr_node_check(struct btr_node *nd, umem_off_t nd_off, report_fn_t report_fn, void *report_arg,
bool error_on_non_zero_padding)
{
uint16_t unknown_flags;
Expand All @@ -4786,37 +4792,37 @@ btr_node_check(struct btr_node *nd, umem_off_t nd_off, btr_report_fn_t report_fn

unknown_flags = nd->tn_flags & ~(BTR_NODE_LEAF | BTR_NODE_ROOT);
if (unknown_flags != 0) {
report_fn(report_arg, BTR_REPORT_ERROR,
report_fn(report_arg, REPORT_ERROR,
CK_BTREE_NODE_MALFORMED_STR "unknown flags (%#" PRIx16 ")",
unknown_flags);
return -DER_NOTYPE;
}

if (nd->tn_pad_32 != 0) {
if (error_on_non_zero_padding) {
report_fn(report_arg, BTR_REPORT_ERROR,
report_fn(report_arg, REPORT_ERROR,
CK_BTREE_NODE_FMT CK_BTREE_NON_ZERO_PADDING_FMT, nd_off,
nd->tn_pad_32);
return -DER_NOTYPE;
} else {
report_fn(report_arg, BTR_REPORT_WARNING,
report_fn(report_arg, REPORT_WARNING,
CK_BTREE_NODE_FMT CK_BTREE_NON_ZERO_PADDING_FMT, nd_off,
nd->tn_pad_32);
}
}

if (nd->tn_gen != 0) {
if (error_on_non_zero_padding) {
report_fn(report_arg, BTR_REPORT_ERROR,
report_fn(report_arg, REPORT_ERROR,
CK_BTREE_NODE_FMT CK_BTREE_NON_ZERO_GEN_FMT, nd_off, nd->tn_gen);
return -DER_NOTYPE;
} else {
report_fn(report_arg, BTR_REPORT_WARNING,
report_fn(report_arg, REPORT_WARNING,
CK_BTREE_NODE_FMT CK_BTREE_NON_ZERO_GEN_FMT, nd_off, nd->tn_gen);
}
}

report_fn(report_arg, BTR_REPORT_MSG, CK_BTREE_NODE_FMT OK_STR, nd_off);
report_fn(report_arg, REPORT_MSG, CK_BTREE_NODE_FMT OK_STR, nd_off);

return DER_SUCCESS;
}
Expand All @@ -4835,28 +4841,30 @@ struct node_info {
* Validate the integrity of a btree.
*
* \param[in] tcx Btree context.
* \param[in] ck Checker.
* \param[in] report_fn Report function.
* \param[in] report_arg Argument for the report function.
*
* \retval DER_SUCCESS The tree is correct.
* \retval -DER_NOTYPE The tree is malformed.
* \retval -DER_NONEXIST The tree is malformed.
* \retval -DER_* Possibly other errors.
*/
static int
btr_nodes_check(struct btr_context *tcx, btr_report_fn_t report_fn, void *report_arg,
btr_nodes_check(struct btr_context *tcx, report_fn_t report_fn, void *report_arg,
bool error_on_non_zero_padding)
{
D_LIST_HEAD(node_list);
struct node_info *ni;
struct node_info *ni_tmp;
umem_off_t nd_off;
struct btr_node *nd;
struct btr_record *rec;
int rc = DER_SUCCESS;

D_ASSERT(report_fn != NULL);

if (btr_root_empty(tcx)) {
report_fn(report_arg, BTR_REPORT_MSG, "Empty tree\n");
report_fn(report_arg, REPORT_MSG, "Empty tree\n");
return DER_SUCCESS;
}

Expand All @@ -4872,23 +4880,38 @@ btr_nodes_check(struct btr_context *tcx, btr_report_fn_t report_fn, void *report
ni = d_list_pop_entry(&node_list, struct node_info, link);
nd_off = ni->nd_off;
nd = btr_off2ptr(tcx, nd_off);
D_FREE(ni);

/** check the node */
rc = btr_node_check(nd, nd_off, report_fn, report_arg, error_on_non_zero_padding);
if (rc != DER_SUCCESS) {
break;
}

/** check records' consistency */
report_fn(report_arg, REPORT_INDENT_INC, NULL);
for (int at = 0; at < nd->tn_keyn; ++at) {
rec = btr_node_rec_at(tcx, nd_off, at);
rc = btr_rec_check(tcx, rec, report_fn, report_arg);
if (rc != DER_SUCCESS) {
break;
}
}
report_fn(report_arg, REPORT_INDENT_DEC, NULL);
if (rc != DER_SUCCESS) {
break;
}

/** a leaf has no child nodes */
if (btr_node_is_leaf(tcx, nd_off)) {
continue;
}

/**
* append the node's children to the front of the nodes' list
* Append the node's children to the front of the nodes' list.
*
* Note: This makes the traversal depth-first. Given the limited depth of a typical
* DAOS tree, this approach should help reduce resource usage.
* Note: This makes the traversal depth-first. Given the limited depth of a
* typical DAOS tree, this approach should help reduce resource usage.
*/
for (int at = 0; at < nd->tn_keyn; ++at) {
D_ALLOC_PTR(ni);
Expand All @@ -4912,11 +4935,14 @@ btr_nodes_check(struct btr_context *tcx, btr_report_fn_t report_fn, void *report
*
* \param[in] root Address of the tree root.
* \param[in] uma Memory class attributes.
* \param[in] ck Checker.
* \param[in] priv Private data for the tree class.
* \param[in] report_fn Report function.
* \param[in] report_arg Argument for the report function.
* \param[in] error_on_non_zero_padding Trigger an error on non-zero padding.
*/
int
dbtree_check_inplace(struct btr_root *root, struct umem_attr *uma, btr_report_fn_t report_fn,
void *report_arg, bool error_on_non_zero_padding)
dbtree_check_inplace(struct btr_root *root, struct umem_attr *uma, void *priv,
report_fn_t report_fn, void *report_arg, bool error_on_non_zero_padding)
{
struct btr_context tcx = {0};
uint64_t tree_feats = -1;
Expand All @@ -4926,7 +4952,7 @@ dbtree_check_inplace(struct btr_root *root, struct umem_attr *uma, btr_report_fn
D_ASSERT(uma != NULL);
D_ASSERT(report_fn != NULL);

rc = btr_class_init(UMOFF_NULL, root, -1, &tree_feats, uma, DAOS_HDL_INVAL, NULL, report_fn,
rc = btr_class_init(UMOFF_NULL, root, -1, &tree_feats, uma, DAOS_HDL_INVAL, priv, report_fn,
report_arg, &tcx.tc_tins);
if (rc != DER_SUCCESS) {
return rc;
Expand Down
34 changes: 22 additions & 12 deletions src/include/daos/btree.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* (C) Copyright 2016-2024 Intel Corporation.
* (C) Copyright 2025 Hewlett Packard Enterprise Development LP
* (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
Expand All @@ -16,6 +16,7 @@
#include <daos/common.h>
#include <daos_types.h>
#include <daos/mem.h>
#include <daos/report.h>

/**
* KV record of the btree.
Expand Down Expand Up @@ -409,7 +410,21 @@ typedef struct {
* \a return Allocated node address (offset within the pool)
*/
umem_off_t (*to_node_alloc)(struct btr_instance *tins, int size);

/**
* Optional:
* Check the consistency of the given record.
*
* \param tins [IN] Tree instance which contains the root umem
* offset and memory class etc.
* \param rec [IN] Record to be checked.
* \param report_fn [IN] Report function.
* \param report_arg [IN] Argument for the report function.
*
* \retval DER_SUCCESS Success.
* \retval -DER_* Errors returned by the fetch callback.
*/
int (*to_rec_check)(struct btr_instance *tins, struct btr_record *rec,
report_fn_t report_fn, void *report_arg);
} btr_ops_t;

/**
Expand Down Expand Up @@ -541,17 +556,12 @@ int dbtree_open(umem_off_t root_off, struct umem_attr *uma,
daos_handle_t *toh);
int dbtree_open_inplace(struct btr_root *root, struct umem_attr *uma,
daos_handle_t *toh);
int dbtree_open_inplace_ex(struct btr_root *root, struct umem_attr *uma,
daos_handle_t coh, void *priv, daos_handle_t *toh);
enum btr_report_type {
BTR_REPORT_ERROR,
BTR_REPORT_WARNING,
BTR_REPORT_MSG,
};
typedef void (*btr_report_fn_t)(void *arg, enum btr_report_type type, const char *fmt, ...);
int
dbtree_check_inplace(struct btr_root *root, struct umem_attr *uma, btr_report_fn_t report_fn,
void *report_arg, bool error_on_non_zero_padding);
dbtree_open_inplace_ex(struct btr_root *root, struct umem_attr *uma, daos_handle_t coh, void *priv,
daos_handle_t *toh);
int
dbtree_check_inplace(struct btr_root *root, struct umem_attr *uma, void *priv,
report_fn_t report_fn, void *report_arg, bool error_on_non_zero_padding);
int dbtree_close(daos_handle_t toh);
int dbtree_destroy(daos_handle_t toh, void *args);
int dbtree_drain(daos_handle_t toh, int *credits, void *args, bool *destroyed);
Expand Down
12 changes: 12 additions & 0 deletions src/include/daos/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,18 @@ enum {
#define DAOS_FAULT_POOL_EXT_PADDING (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x209)
#define DAOS_FAULT_POOL_EXT_RESERVED (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x20a)

/** Container open fault injection */
#define DAOS_FAULT_CONT_DOES_NOT_EXIST (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x300)
#define DAOS_FAULT_CONT_OPEN_UUID (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x301)
#define DAOS_FAULT_CONT_INV_PAD (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x302)
#define DAOS_FAULT_CONT_INV_USED (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x303)
#define DAOS_FAULT_CONT_INV_RESERV_UPGRADE (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x304)
#define DAOS_FAULT_DBD_MAGIC (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x305)
#define DAOS_FAULT_DAE_INV_FLAGS (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x306)
#define DAOS_FAULT_DAE_ALLOC (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x307)
#define DAOS_FAULT_DBD_COUNT (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x308)
#define DAOS_FAULT_OBJ_ILOG_MAGIC (DAOS_FAIL_SYS_TEST_GROUP_LOC | 0x309)

#define DAOS_DTX_SKIP_PREPARE DAOS_DTX_SPEC_LEADER

#define DAOS_FAIL_CHECK(id) daos_fail_check(id)
Expand Down
28 changes: 28 additions & 0 deletions src/include/daos/report.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* (C) Copyright 2026 Hewlett Packard Enterprise Development LP
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/

#ifndef __DAOS_REPORT_H__
#define __DAOS_REPORT_H__

enum report_opts {
REPORT_ERROR,
REPORT_WARNING,
REPORT_MSG,
/** flags occupy the highest bits */
REPORT_NO_PREFIX = (1 << 29),
REPORT_INDENT_INC = (1 << 30),
REPORT_INDENT_DEC = (1 << 31),
REPORT_FLAGS_MASK = (REPORT_NO_PREFIX | REPORT_INDENT_INC | REPORT_INDENT_DEC),
};

typedef void (*report_fn_t)(void *arg, enum report_opts opts, const char *fmt, ...);

static inline void
report_fn_nop(void *arg, enum report_opts ops, const char *fmt, ...)
{
}

#endif /* __DAOS_REPORT_H__ */
Loading
Loading