For a use case where you want to traverse large lists / tables and reply fast you want to implement ConfD’s get_next_object() and find_next_object() DP API callbacks.
Here is a short example on how to optimize a your replies for data when you want to traverse large lists / tables fast.
We start out with a very simple YANG data model that implements a list / table called “port” which has two keys and a three more leafs in it:
list port {
key "slot port”;
config false;
tailf:callpoint ps {
tailf:cache true;
}
leaf slot {
type int8;
}
leaf port {
type int8;
}
leaf status {
type enumeration {
enum "disabled";
enum "active";
enum "error";
}
mandatory true;
}
leaf extra {
type int32;
}
leaf flag {
type empty;
}
}
This is the desired end result, here shown from the ConfD CLI:
admin@ncsvm> show port
SLOT PORT STATUS EXTRA FLAG
-----------------------------------
1 0 disabled 1 -
1 1 active 2 X
1 2 error 3 -
2 1 disabled 4 X
2 2 active 5 -
4 0 error 6 X
4 2 disabled 7 -
In this example we register our data callbacks for our callpoint from the YANG data module in the main() function of our program:
int main(int argc, char *argv[])
{
...
struct confd_data_cbs data;
...
data.get_object = get_object;
data.get_next_object = get_next_object; /* We implement these callbacks to be able to traverse a list/table very fast */
data.find_next_object = find_next_object;
...
strcpy(data.callpoint, ports__callpointid_ps);
confd_register_data_cb(dctx, &data);
...
}
Our get_next_object() data callback then return the whole list / table in one swoop:
static int get_next_object(struct confd_trans_ctx *tctx,
confd_hkeypath_t *keypath, long next)
{
int pos, ival, i;
confd_value_t *v;
struct confd_next_object *obj;
...
if (next == -1) {
pos = 0; /* ConfD wants to get the whole table / list from the beginning */
} else if (next < n_list_entries) {
pos = next; /* ConfD wants the table / list from a specific index */
} else { /* next == n_list_entries, return nothing */
confd_data_reply_next_object_array(tctx, NULL, -1, -1);
return CONFD_OK;
}
...
obj = malloc(sizeof(struct confd_next_object) * (n_list_entries + 2));
v = (confd_value_t *) malloc(sizeof(confd_value_t) * n_list_entries * N_LEAFS);
...
for (i = 0; pos + i < n_list_entries; i++) { /* Collect all the rows in the table / list entries */
obj[i].v = &v[i * N_LEAFS];
...
CONFD_SET_INT8(&(obj[i].v[0]), ival); /* List key leaf slot int8 */
...
CONFD_SET_INT8(&(obj[i].v[1]), ival); /* List key leaf port int8 */
...
CONFD_SET_ENUM_HASH(&(obj[i].v[2]), ival); /* Leaf status enumeration */
...
CONFD_SET_INT32(&(obj[i].v[3]), ival); /* Leaf extra int32 */
...
if (ival) /* Leaf flag */
CONFD_SET_XMLTAG(&(obj[i].v[4]), ports_flag, ports__ns);
else
CONFD_SET_NOEXISTS(&(obj[i].v[4]));
obj[i].n = N_LEAFS;
obj[i].next = (long)pos + i + 1; /* Tell ConfD where next object is, if we did not get all of the rows in the table / list entries */
}
if (pos + i == n_list_entries)
obj[i++].v = NULL;
confd_data_reply_next_object_arrays(tctx, obj, i, 0); /* Reply with an array of object arrays. I.e. the whole table / list */
free(v);
free(obj);
return CONFD_OK;
}
With this implementation of get_next_object() ConfD will return the whole table / list in one single swoop. I.e. there will be only one call to a data callback, in this example the get_next_object() callback. This is useful if you have large tables / lists of data that need to be fetched and want to tune your performance for that use case. If users normally just wants a single entry or just a list entry / table row, using get_elem() or get_object() and find_next() will provide better performance.
You can learn more about ConfD data provider callpoints and associated data callbacks in Volume 3 of the ConfD man-pages under the confd_lib_dp section confd_register_data_cb() function.