diff --git a/apps/backend/backend_get.c b/apps/backend/backend_get.c index 30639cf2..9fe72229 100644 --- a/apps/backend/backend_get.c +++ b/apps/backend/backend_get.c @@ -258,7 +258,7 @@ get_client_statedata(clicon_handle h, goto fail; } /* Use plugin state callbacks */ - if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, PAGING_NONE, 0, 0, xret)) < 0) + if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, PAGING_NONE, 0, 0, NULL, xret)) < 0) goto done; if (ret == 0) goto fail; @@ -470,13 +470,11 @@ get_list_pagination(clicon_handle h, char *xpath2; /* With optional paging predicate */ int ret; uint32_t iddb; /* DBs lock, if any */ - enum paging_status pagingstatus; + paging_status_t pagingstatus; cxobj *x1 = NULL; -#ifdef LIST_PAGINATION_REMAINING cxobj *xcache = NULL; uint32_t total = 0; uint32_t remaining = 0; -#endif /* Check if list/leaf-list */ if (yang_path_arg(yspec, xpath, &ylist) < 0) @@ -566,26 +564,6 @@ get_list_pagination(clicon_handle h, cprintf(cbpath, "[position() < %u]", limit); /* Append predicate to original xpath and replace it */ xpath2 = cbuf_get(cbpath); -#ifdef LIST_PAGINATION_REMAINING - /* Get total/remaining - * XXX: Works only for cache, and only if already populated - * XXX: Maybe together with get config / state data - */ - if (list_config){ - if ((xcache = xmldb_cache_get(h, db)) != NULL){ - if (xpath_count(xcache, nsc, xpath, &total) < 0) - goto done; - if (total >= (offset + limit)) - remaining = total - (offset + limit); - } - } - else{ - /* Remaining of state list. Two strategies: - * 1. New api where state callback is registered, lock, iterative, unlock - * 2. Read all here and count (fallback) - */ - } -#endif /* LIST_PAGINATION_REMAINING */ /* Read config */ switch (content){ case CONTENT_CONFIG: /* config data only */ @@ -607,8 +585,19 @@ get_list_pagination(clicon_handle h, goto done; break; }/* switch content */ - if (!list_config){ - /* Check if running locked (by this session) */ + + if (list_config){ + /* Get total/remaining + * XXX: Works only for cache + */ + if ((xcache = xmldb_cache_get(h, db)) != NULL){ + if (xpath_count(xcache, nsc, xpath, &total) < 0) + goto done; + if (total >= (offset + limit)) + remaining = total - (offset + limit); + } + } + else {/* Check if running locked (by this session) */ if ((iddb = xmldb_islocked(h, "running")) != 0 && iddb == ce->ce_id) pagingstatus = PAGING_LOCK; @@ -617,7 +606,7 @@ get_list_pagination(clicon_handle h, /* Use plugin state callbacks */ if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, pagingstatus, - offset, limit, &xret)) < 0) + offset, limit, &remaining, &xret)) < 0) goto done; } if (filter_xpath_again(h, yspec, xret, xpath, nsc, &x1) < 0) diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 8cbf20f4..bc3576f7 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -242,6 +242,7 @@ clixon_plugin_daemon_all(clicon_handle h) * @param[in] pagingstatus List pagination status * @param[in] offset Offset, for list pagination * @param[in] limit Limit, for list pagination + * @param[out] remaining Remaining elements (if limit is non-zero) * @param[out] xp If retval=1, state tree created and returned: ... * @retval -1 Fatal error * @retval 0 Statedata callback failed. no XML tree returned @@ -252,9 +253,10 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, clicon_handle h, cvec *nsc, char *xpath, - enum paging_status pagingstatus, + paging_status_t pagingstatus, uint32_t offset, uint32_t limit, + uint32_t *remaining, cxobj **xp) { int retval = -1; @@ -266,7 +268,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, if ((fn2 = clixon_plugin_api_get(cp)->ca_statedata2) != NULL){ if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL) goto done; - if (fn2(h, nsc, xpath, pagingstatus, offset, limit, x) < 0){ + if (fn2(h, nsc, xpath, pagingstatus, offset, limit, remaining, x) < 0){ if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: State callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, clixon_plugin_name_get(cp)); @@ -303,6 +305,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, * @param[in] pagination List pagination * @param[in] offset Offset, for list pagination * @param[in] limit Limit, for list pagination + * @param[out] remaining Remaining elements (if limit is non-zero) * @param[in,out] xret State XML tree is merged with existing tree. * @retval -1 Error * @retval 0 Statedata callback failed (xret set with netconf-error) @@ -310,14 +313,15 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, * @note xret can be replaced in this function */ int -clixon_plugin_statedata_all(clicon_handle h, - yang_stmt *yspec, - cvec *nsc, - char *xpath, - enum paging_status pagingstatus, - uint32_t offset, - uint32_t limit, - cxobj **xret) +clixon_plugin_statedata_all(clicon_handle h, + yang_stmt *yspec, + cvec *nsc, + char *xpath, + paging_status_t pagingstatus, + uint32_t offset, + uint32_t limit, + uint32_t *remaining, + cxobj **xret) { int retval = -1; int ret; @@ -329,7 +333,7 @@ clixon_plugin_statedata_all(clicon_handle h, clicon_debug(1, "%s", __FUNCTION__); while ((cp = clixon_plugin_each(h, cp)) != NULL) { if ((ret = clixon_plugin_statedata_one(cp, h, nsc, xpath, pagingstatus, - offset, limit, &x)) < 0) + offset, limit, remaining, &x)) < 0) goto done; if (ret == 0){ if ((cberr = cbuf_new()) == NULL){ diff --git a/apps/backend/clixon_backend_plugin.h b/apps/backend/clixon_backend_plugin.h index 1178f66d..b88c58e8 100644 --- a/apps/backend/clixon_backend_plugin.h +++ b/apps/backend/clixon_backend_plugin.h @@ -76,8 +76,9 @@ int clixon_plugin_pre_daemon_all(clicon_handle h); int clixon_plugin_daemon_all(clicon_handle h); int clixon_plugin_statedata_all(clicon_handle h, yang_stmt *yspec, cvec *nsc, char *xpath, - enum paging_status pagingstatus, - uint32_t offset, uint32_t limit, cxobj **xtop); + paging_status_t pagingstatus, + uint32_t offset, uint32_t limit, uint32_t *remaining, + cxobj **xtop); int clixon_plugin_lockdb_all(clicon_handle h, char *db, int lock, int id); transaction_data_t * transaction_new(void); diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 8e65a160..fc89414c 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -896,7 +896,7 @@ cli_show_options(clicon_handle h, /*! Show pagination * @param[in] h Clicon handle * @param[in] cvv Vector of cli string and instantiated variables - * @param[in] argv Vector. Format: + * @param[in] argv Vector. Format: * Also, if there is a cligen variable called "xpath" it will override argv xpath arg */ int @@ -918,12 +918,12 @@ cli_pagination(clicon_handle h, cg_var *cv; int i; int j; - int window = 0; + uint32_t limit = 0; cxobj **xvec = NULL; size_t xlen; if (cvec_len(argv) != 5){ - clicon_err(OE_PLUGIN, 0, "Expected usage: "); + clicon_err(OE_PLUGIN, 0, "Expected usage: "); goto done; } /* prefix:variable overrides argv */ @@ -939,13 +939,13 @@ cli_pagination(clicon_handle h, goto done; } if ((str = cv_string_get(cvec_i(argv, 4))) != NULL){ - if (parse_int32(str, &window, NULL) < 1){ - clicon_err(OE_UNIX, errno, "error parsing window integer:%s", str); + if (parse_uint32(str, &limit, NULL) < 1){ + clicon_err(OE_UNIX, errno, "error parsing limit:%s", str); goto done; } } - if (window == 0){ - clicon_err(OE_UNIX, EINVAL, "window is 0"); + if (limit == 0){ + clicon_err(OE_UNIX, EINVAL, "limit is 0"); goto done; } if ((nsc = xml_nsctx_init(prefix, namespace)) == NULL) @@ -956,8 +956,8 @@ cli_pagination(clicon_handle h, if (clicon_rpc_get_pageable_list(h, "running", xpath, nsc, CONTENT_ALL, -1, /* depth */ - window*i, /* offset */ - window, /* limit */ + limit*i, /* offset */ + limit, /* limit */ NULL, NULL, NULL, /* nyi */ &xret) < 0){ goto done; @@ -988,10 +988,10 @@ cli_pagination(clicon_handle h, } if (cli_output_status() < 0) break; - } + } /* for j */ if (cli_output_status() < 0) break; - if (xlen != window) /* Break if fewer elements than requested */ + if (xlen != limit) /* Break if fewer elements than requested */ break; if (xret){ xml_free(xret); @@ -1001,7 +1001,7 @@ cli_pagination(clicon_handle h, free(xvec); xvec = NULL; } - } /* for */ + } /* for i */ if (clicon_rpc_unlock(h, "running") < 0) goto done; retval = 0; diff --git a/example/main/example_backend.c b/example/main/example_backend.c index 57ca70ce..19aebd01 100644 --- a/example/main/example_backend.c +++ b/example/main/example_backend.c @@ -356,7 +356,8 @@ example_copy_extra(clicon_handle h, /* Clicon handle */ * @param[in] paging List pagination (not uses here) * @param[in] offset Offset, for list pagination * @param[in] limit Limit, for list pagination - * @param[in] xstate XML tree, on entry. + * @param[out] remaining Remaining elements (if limit is non-zero) + * @param[out] xstate XML tree, on entry. * @retval 0 OK * @retval -1 Error * @see xmldb_get @@ -373,13 +374,14 @@ example_copy_extra(clicon_handle h, /* Clicon handle */ * @see example_statefile where state is read from file and also paging */ int -example_statedata(clicon_handle h, - cvec *nsc, - char *xpath, - enum paging_status paging, - uint32_t offset, - uint32_t limit, - cxobj *xstate) +example_statedata(clicon_handle h, + cvec *nsc, + char *xpath, + paging_status_t paging, + uint32_t offset, + uint32_t limit, + uint32_t *remaining, + cxobj *xstate) { int retval = -1; cxobj **xvec = NULL; @@ -464,20 +466,21 @@ example_statedata(clicon_handle h, * @param[in] paging List pagination * @param[in] offset Offset, for list pagination * @param[in] limit Limit, for list pagination - * @param[in] xstate XML tree, on entry. Copy to this + * @param[out] xstate XML tree, on entry. Copy to this * @retval 0 OK * @retval -1 Error * @see xmldb_get * @see example_statefile where state is programmatically added */ int -example_statefile(clicon_handle h, - cvec *nsc, - char *xpath, - enum paging_status paging, - uint32_t offset, - uint32_t limit, - cxobj *xstate) +example_statefile(clicon_handle h, + cvec *nsc, + char *xpath, + paging_status_t paging, + uint32_t offset, + uint32_t limit, + uint32_t *remaining, + cxobj *xstate) { int retval = -1; cxobj **xvec = NULL; @@ -506,15 +509,6 @@ example_statefile(clicon_handle h, goto done; if ((ret = clixon_xml_parse_file(fp, YB_MODULE, yspec, &xt, NULL)) < 0) goto done; -#if 0 - if (ret == 0){ - if (clixon_netconf_internal_error(xstate, - ". Internal error, state callback returned invalid XML", - NULL) < 0) - goto done; - goto ok; - } -#endif if (_state_file_cached) _state_xml_cache = xt; } @@ -535,6 +529,7 @@ example_statefile(clicon_handle h, else{ if ((upper = offset+limit)>xlen) upper = xlen; + *remaining = xlen - upper; } break; } diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index d256f399..e60b0542 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -52,7 +52,7 @@ * modified, and these changes have not been committed or rolled back. */ typedef struct { - uint32_t de_id; /* session id keeps lock */ + uint32_t de_id; /* If set, lockaed by this client/session id */ cxobj *de_xml; /* cache */ int de_modified; /* Dirty since loaded/copied/committed/etc XXX:nocache? */ int de_empty; /* Empty on read from file, xmldb_readfile and xmldb_put sets it */ diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index d1c7962c..7d08b0ba 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -224,21 +224,24 @@ enum paging_status{ PAGING_STATELESS, /* Stateless list paging, dont expect more paging calls */ PAGING_LOCK /* Transactional list paging, can expect more paging until lock release */ }; +typedef enum paging_status paging_status_t; /* Plugin statedata * @param[in] Clicon handle * @param[in] xpath Part of state requested * @param[in] nsc XPATH namespace context. - * @param[in] pagination List pagination: 0: No, 1: begin/next, 2: end + * @param[in] paging List pagination mode * @param[in] offset Offset, for list pagination * @param[in] limit Limit, for list pagination + * @param[out] remaining Remaining elements (if limit is non-zero) * @param[out] xtop XML tree where statedata is added * @retval -1 Fatal error * @retval 0 OK */ typedef int (plgstatedata2_t)(clicon_handle h, cvec *nsc, char *xpath, - enum paging_status pagination, - uint32_t offset, uint32_t limit, + paging_status_t paging, + uint32_t offset, uint32_t limit, + uint32_t *remaining, cxobj *xtop); /*! Lock databse status has changed status diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index d4745aab..aaf2c233 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -313,7 +313,7 @@ xml2cli_recurse(FILE *f, } ok: retval = 0; - done: + done: if (cbpre) cbuf_free(cbpre); return retval; diff --git a/test/test_paging_state.sh b/test/test_paging_state.sh index f145bd7e..c744fb68 100755 --- a/test/test_paging_state.sh +++ b/test/test_paging_state.sh @@ -87,10 +87,11 @@ fi new "wait backend" wait_backend -# XXX How to run without using a terminal? +# XXX How to run without using a terminal? Maybe use expect/unbuffer new "cli show" echo "$clixon_cli -1 -f $cfg -l o show pagination xpath /es:audit-logs/es:audit-log cli" $clixon_cli -1 -f $cfg -l o show pagination xpath /es:audit-logs/es:audit-log cli +#expectpart "$(echo -n | unbuffer -p $clixon_cli -1 -f $cfg -l o show pagination xpath /es:audit-logs/es:audit-log cli)" 0 foo if [ $BE -ne 0 ]; then new "Kill backend"