#include <freeradius-devel/util/stats.h>
-// convert a set of pairs to a struct
-
/** Convert a statistics structure to #fr_pair_t
*
* @param[in] ctx talloc ctx
return 0;
}
-int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *inst, fr_pair_list_t *in)
+
+/** Convert a statistics structure to #fr_pair_t
+ *
+ * @param[in] ctx talloc ctx
+ * @param[out] inst where the output pairs will be stored
+ * @param[in] list pairs where we read the pairs from
+ */
+int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *inst, fr_pair_list_t const *list)
{
size_t i;
fr_stats_link_t const *def = inst->def;
uint8_t *out = inst->stats;
fr_pair_t const *parent, *vp;
- parent = fr_pair_find_by_da(in, NULL, *(def->root_p));
+ parent = fr_pair_find_by_da(list, NULL, *(def->root_p));
if (!parent) return -1;
memset(out, 0, inst->def->size);
/** Public API for merging two statistics structures
*
+ * @param[out] out where the merged stats are written to
+ * @param[in] in source stats to merge into out
+ * @return
+ * - 0 on success
+ * - <0 on the two instances are not compatible.
*/
-int fr_stats_merge(fr_stats_instance_t *out, fr_stats_instance_t const *in)
+int fr_stats_merge_instance(fr_stats_instance_t *out, fr_stats_instance_t const *in)
{
if (out->def != in->def) {
fr_strerror_printf("Cannot merge stats into structure %s from different structure %s",
return stats_merge_internal(out->def, out->stats, in->stats);
}
+/** Public API for merging two value-boxes based on their enums
+ *
+ * @param[in,out] dst where the merged stats are written to
+ * @param[in] src source stats to merge into dst
+ * @return
+ * - 0 on success
+ * - <0 on the two boxes are not compatible, or we cannot merge the given data type
+ */
+int fr_stats_merge_value_box(fr_value_box_t *dst, fr_value_box_t const *src)
+{
+ if (dst->type != src->type) {
+ fr_strerror_const("Cannot merge two different data types");
+ return -1;
+ }
+
+ if (dst->enumv != src->enumv) {
+ fr_strerror_const("Cannot merge two different fields");
+ return -1;
+ }
+
+ if (!dst->enumv) {
+ fr_strerror_const("Unable to determine how to merge the fields");
+ return -1;
+ }
+
+ /*
+ * @todo - distinguish counter from gauge. This also means that we will need to update the
+ * dictionary.stats to set the "counter" flag.
+ */
+
+ switch (dst->type) {
+ case FR_TYPE_UINT16:
+ dst->vb_uint16 += src->vb_uint16;
+ break;
+
+ case FR_TYPE_UINT32:
+ dst->vb_uint32 += src->vb_uint32;
+ break;
+
+ case FR_TYPE_UINT64:
+ dst->vb_uint64 += src->vb_uint64;
+ break;
+
+ default:
+ fr_strerror_const("Cannot merge non-integer data types");
+ return -1;
+ }
-void fr_stats_iter_init(fr_stats_instance_t const *in, fr_stats_iter_t *iter)
+ return 0;
+}
+
+
+/** Initialize an iterator over a structure
+ *
+ * @param[in] inst data structure defining this instance of the statistics
+ * @param[out] iter the initialized iterator
+ */
+void fr_stats_iter_init(fr_stats_instance_t const *inst, fr_stats_iter_t *iter)
{
- iter->inst = in;
+ iter->inst = inst;
iter->current = 0;
}
+/** Go to the next entry in a structure
+ *
+ * @param[in] iter the iterator
+ * @return
+ * - true for continue the iteration
+ * - false for the iteration is done
+ */
bool fr_stats_iter_next(fr_stats_iter_t *iter)
{
if (iter->current < iter->inst->def->num_elements) {
return false;
}
+
+/** Convert the statistic at an index to a value-box
+ *
+ * @param[in] ctx the talloc context
+ * @param[out] out the value-box to return
+ * @param[in] inst data structure defining this instance of the statistics
+ * @param[in] index the field index of the structure to use
+ * @return
+ * - 0 for success, and *out is non-NULL
+ * - <0 for error (memory allocation failed, index is invalid, etc), and *out is NULL
+ */
int fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_instance_t const *inst, unsigned int index)
{
size_t len;
uint8_t const *field;
fr_dict_attr_t const *da;
- if (index >= inst->def->num_elements) return 0;
+ if (index >= inst->def->num_elements) {
+ fail:
+ *out = NULL;
+ return -1;
+ }
da = *(inst->def->entry[index].da_p);
fr_assert(da != NULL);
box = fr_value_box_alloc(ctx, inst->def->entry[index].type, da);
- if (!box) return -1;
+ if (!box) goto fail;
field = ((uint8_t const *) inst->stats) + inst->def->entry[index].offset;
default:
fr_strerror_printf("Unsupported data type '%s'", fr_type_to_str(box->type));
- return -1;
+ goto fail_free;
}
if (fr_value_box_from_memory(box, box, box->type, da, field, len) < 0) {
+ fail_free:
talloc_free(box);
- return -1;
+ goto fail;
}
*out = box;
}
+/** Convert the statistic at the current iterator to a value-box
+ *
+ * @param[in] ctx the talloc context
+ * @param[out] out the value-box to return
+ * @param[in] iter the iterator, which points to the current entry.
+ * @return
+ * - 0 for success, and *out is non-NULL
+ * - <0 for error (memory allocation failed, index is invalid, etc), and *out is NULL
+ */
int fr_stats_iter_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_iter_t *iter)
{
fr_assert(iter->inst);
return fr_stats_index_to_value_box(ctx, out, iter->inst, iter->current);
}
+
+
+/** Convert the statistic of a given name to a value-box
+ *
+ * @param[in] ctx the talloc context
+ * @param[out] out the value-box to return
+ * @param[in] inst data structure defining this instance of the statistics
+ * @param[in] name the field name in the structure
+ * @return
+ * - 0 for success, and *out is non-NULL
+ * - <0 for error (memory allocation failed, name is invalid, etc), and *out is NULL
+ */
+int fr_stats_name_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_instance_t const *inst, char const *name)
+{
+ fr_dict_attr_t const *da;
+
+ da = fr_dict_attr_by_name(NULL, *inst->def->root_p, name);
+ if (!da) return -1;
+
+ return fr_stats_index_to_value_box(ctx, out, inst, da->attr);
+}
#define FR_STATS_FIELD(_var, _field) (_var)->stats.(_field)
int fr_stats_to_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
-int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *out, fr_pair_list_t *in) CC_HINT(nonnull);
-int fr_stats_merge(fr_stats_instance_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
+int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *out, fr_pair_list_t const *list) CC_HINT(nonnull);
+int fr_stats_merge_instance(fr_stats_instance_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
+int fr_stats_merge_value_box(fr_value_box_t *dst, fr_value_box_t const *src) CC_HINT(nonnull);
void fr_stats_iter_init(fr_stats_instance_t const *in, fr_stats_iter_t *iter) CC_HINT(nonnull);
bool fr_stats_iter_next(fr_stats_iter_t *iter) CC_HINT(nonnull);
int fr_stats_iter_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_iter_t *iter) CC_HINT(nonnull);
-int fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_instance_t const *in, unsigned int index) CC_HINT(nonnull);
+int fr_stats_index_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out,
+ fr_stats_instance_t const *in, unsigned int index) CC_HINT(nonnull);
+int fr_stats_name_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out,
+ fr_stats_instance_t const *inst, char const *name) CC_HINT(nonnull);
#ifdef __cplusplus