* New state callback signature (ca_statedata2)
* The new callback contains parameters for paging * Goal is to replace ca_statedata callback * New plugin callback when lock/unlock occurs * Add `ca_lockdb` tro plugin init to use it. * Fixed: Typing 'q' in CLI more paging did not properly quit output * Output continued but was not shown, for a very large file this could cause considerable delay * Fixed: Lock was broken in first get get access * if the first netconf operation to a backend was lock;get;unlock, the lock was broken in the first get access.
This commit is contained in:
parent
aaf9a89183
commit
caabfd464e
15 changed files with 487 additions and 233 deletions
|
|
@ -122,6 +122,37 @@ ce_event_cb(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Unlock all db:s of a client and call user unlock calback
|
||||
* @see xmldb_unlock_all unlocks, but does not call user callbacks which is a backend thing
|
||||
*/
|
||||
static int
|
||||
release_all_dbs(clicon_handle h,
|
||||
uint32_t id)
|
||||
{
|
||||
int retval = -1;
|
||||
char **keys = NULL;
|
||||
size_t klen;
|
||||
int i;
|
||||
db_elmnt *de;
|
||||
|
||||
/* get all db:s */
|
||||
if (clicon_hash_keys(clicon_db_elmnt(h), &keys, &klen) < 0)
|
||||
goto done;
|
||||
/* Identify the ones locked by client id */
|
||||
for (i = 0; i < klen; i++) {
|
||||
if ((de = clicon_db_elmnt_get(h, keys[i])) != NULL &&
|
||||
de->de_id == id){
|
||||
de->de_id = 0; /* unlock */
|
||||
clicon_db_elmnt_set(h, keys[i], de);
|
||||
if (clixon_plugin_lockdb_all(h, keys[i], 0, id) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Remove client entry state
|
||||
* Close down everything wrt clients (eg sockets, subscriptions)
|
||||
* Finally actually remove client struct in handle
|
||||
|
|
@ -148,7 +179,8 @@ backend_client_rm(clicon_handle h,
|
|||
clixon_event_unreg_fd(ce->ce_s, from_client);
|
||||
close(ce->ce_s);
|
||||
ce->ce_s = 0;
|
||||
xmldb_unlock_all(h, ce->ce_id);
|
||||
if (release_all_dbs(h, ce->ce_id) < 0)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -606,6 +638,9 @@ from_client_lock(clicon_handle h,
|
|||
}
|
||||
if (xmldb_lock(h, db, id) < 0)
|
||||
goto done;
|
||||
/* user callback */
|
||||
if (clixon_plugin_lockdb_all(h, db, 1, id) < 0)
|
||||
goto done;
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
@ -677,6 +712,9 @@ from_client_unlock(clicon_handle h,
|
|||
}
|
||||
else{
|
||||
xmldb_unlock(h, db);
|
||||
/* user callback */
|
||||
if (clixon_plugin_lockdb_all(h, db, 0, id) < 0)
|
||||
goto done;
|
||||
if (cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -699,15 +737,16 @@ from_client_unlock(clicon_handle h,
|
|||
*/
|
||||
static int
|
||||
from_client_close_session(clicon_handle h,
|
||||
cxobj *xe,
|
||||
cbuf *cbret,
|
||||
void *arg,
|
||||
void *regarg)
|
||||
cxobj *xe,
|
||||
cbuf *cbret,
|
||||
void *arg,
|
||||
void *regarg)
|
||||
{
|
||||
struct client_entry *ce = (struct client_entry *)arg;
|
||||
uint32_t id = ce->ce_id;
|
||||
|
||||
xmldb_unlock_all(h, id);
|
||||
if (release_all_dbs(h, id) < 0)
|
||||
return -1;
|
||||
stream_ss_delete_all(h, ce_event_cb, (void*)ce);
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
|
||||
return 0;
|
||||
|
|
@ -751,11 +790,16 @@ from_client_kill_session(clicon_handle h,
|
|||
goto ok;
|
||||
/* may or may not be in active client list, probably not */
|
||||
if ((ce = ce_find_byid(backend_client_list(h), id)) != NULL){
|
||||
xmldb_unlock_all(h, id); /* Removes locks on all databases */
|
||||
if (release_all_dbs(h, id) < 0)
|
||||
goto done;
|
||||
backend_client_rm(h, ce); /* Removes client struct */
|
||||
}
|
||||
if (xmldb_islocked(h, db) == id)
|
||||
if (xmldb_islocked(h, db) == id){
|
||||
xmldb_unlock(h, db);
|
||||
/* user callback */
|
||||
if (clixon_plugin_lockdb_all(h, db, 0, id) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
#include "clixon_backend_handle.h"
|
||||
#include "clixon_backend_plugin.h"
|
||||
#include "clixon_backend_commit.h"
|
||||
#include "backend_client.h"
|
||||
#include "backend_handle.h"
|
||||
#include "backend_get.h"
|
||||
|
||||
|
|
@ -260,7 +261,7 @@ get_client_statedata(clicon_handle h,
|
|||
goto fail;
|
||||
}
|
||||
/* Use plugin state callbacks */
|
||||
if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, 0, 0, xret)) < 0)
|
||||
if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, PAGING_NONE, 0, 0, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -313,6 +314,7 @@ element2value(clicon_handle h,
|
|||
* It is specialized enough to have its own function. Specifically, extra attributes as well
|
||||
* as the list-paginaiton API
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] ce Client entry, for locking
|
||||
* @param[in] xe Request: <rpc><xn></rpc>
|
||||
* @param[in] content Get config/state/both
|
||||
* @param[in] db Database name
|
||||
|
|
@ -326,16 +328,17 @@ element2value(clicon_handle h,
|
|||
* XXX Lots of this code (in particular at the end) is copy of get_common
|
||||
*/
|
||||
static int
|
||||
get_list_pagination(clicon_handle h,
|
||||
cxobj *xe,
|
||||
netconf_content content,
|
||||
char *db,
|
||||
int32_t depth,
|
||||
yang_stmt *yspec,
|
||||
char *xpath,
|
||||
cvec *nsc,
|
||||
char *username,
|
||||
cbuf *cbret
|
||||
get_list_pagination(clicon_handle h,
|
||||
struct client_entry *ce,
|
||||
cxobj *xe,
|
||||
netconf_content content,
|
||||
char *db,
|
||||
int32_t depth,
|
||||
yang_stmt *yspec,
|
||||
char *xpath,
|
||||
cvec *nsc,
|
||||
char *username,
|
||||
cbuf *cbret
|
||||
)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -359,6 +362,8 @@ get_list_pagination(clicon_handle h,
|
|||
int ret;
|
||||
int i;
|
||||
cxobj *xnacm = NULL;
|
||||
uint32_t iddb; /* DBs lock, if any */
|
||||
enum paging_status pagingstatus;
|
||||
#ifdef REMAINING
|
||||
cxobj *xcache = NULL;
|
||||
uint32_t total = 0;
|
||||
|
|
@ -495,11 +500,16 @@ get_list_pagination(clicon_handle h,
|
|||
break;
|
||||
}/* switch content */
|
||||
if (!list_config){
|
||||
/* Look if registered,
|
||||
* get all state list and filter using cbpath
|
||||
*/
|
||||
/* Check if running locked (by this session) */
|
||||
if ((iddb = xmldb_islocked(h, "running")) != 0 &&
|
||||
iddb == ce->ce_id)
|
||||
pagingstatus = PAGING_LOCK;
|
||||
else
|
||||
pagingstatus = PAGING_STATELESS;
|
||||
/* Use plugin state callbacks */
|
||||
if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, offset, limit, &xret)) < 0)
|
||||
if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath,
|
||||
pagingstatus,
|
||||
offset, limit, &xret)) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Code complex to filter out anything that is outside of xpath
|
||||
|
|
@ -603,6 +613,7 @@ get_list_pagination(clicon_handle h,
|
|||
/*! Common get/get-config code for retrieving configuration and state information.
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] ce Client entry, for locking
|
||||
* @param[in] xe Request: <rpc><xn></rpc>
|
||||
* @param[in] content Get config/state/both
|
||||
* @param[in] db Database name
|
||||
|
|
@ -613,11 +624,12 @@ get_list_pagination(clicon_handle h,
|
|||
* @see from_client_get_config
|
||||
*/
|
||||
static int
|
||||
get_common(clicon_handle h,
|
||||
cxobj *xe,
|
||||
netconf_content content,
|
||||
char *db,
|
||||
cbuf *cbret
|
||||
get_common(clicon_handle h,
|
||||
struct client_entry *ce,
|
||||
cxobj *xe,
|
||||
netconf_content content,
|
||||
char *db,
|
||||
cbuf *cbret
|
||||
)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -696,7 +708,7 @@ get_common(clicon_handle h,
|
|||
* check config/state
|
||||
*/
|
||||
if (list_pagination){
|
||||
if (get_list_pagination(h, xe, content, db,
|
||||
if (get_list_pagination(h, ce, xe, content, db,
|
||||
depth, yspec, xpath, nsc, username,
|
||||
cbret) < 0)
|
||||
goto done;
|
||||
|
|
@ -901,14 +913,15 @@ from_client_get_config(clicon_handle h,
|
|||
void *arg,
|
||||
void *regarg)
|
||||
{
|
||||
int retval = -1;
|
||||
char *db;
|
||||
int retval = -1;
|
||||
char *db;
|
||||
struct client_entry *ce = (struct client_entry *)arg;
|
||||
|
||||
if ((db = netconf_db_find(xe, "source")) == NULL){
|
||||
clicon_err(OE_XML, 0, "db not found");
|
||||
goto done;
|
||||
}
|
||||
retval = get_common(h, xe, CONTENT_CONFIG, db, cbret);
|
||||
retval = get_common(h, ce, xe, CONTENT_CONFIG, db, cbret);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -932,11 +945,12 @@ from_client_get(clicon_handle h,
|
|||
void *arg,
|
||||
void *regarg)
|
||||
{
|
||||
netconf_content content = CONTENT_ALL;
|
||||
char *attr;
|
||||
netconf_content content = CONTENT_ALL;
|
||||
char *attr;
|
||||
struct client_entry *ce = (struct client_entry *)arg;
|
||||
|
||||
/* Clixon extensions: content */
|
||||
if ((attr = xml_find_value(xe, "content")) != NULL)
|
||||
content = netconf_content_str2int(attr);
|
||||
return get_common(h, xe, content, "running", cbret);
|
||||
return get_common(h, ce, xe, content, "running", cbret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ clixon_plugin_daemon_all(clicon_handle h)
|
|||
* @param[in] h clicon handle
|
||||
* @param[in] nsc namespace context for xpath
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in] pagingstatus List pagination status
|
||||
* @param[in] offset Offset, for list pagination
|
||||
* @param[in] limit Limit, for list pagination
|
||||
* @param[out] xp If retval=1, state tree created and returned: <config>...
|
||||
|
|
@ -251,6 +252,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
|
|||
clicon_handle h,
|
||||
cvec *nsc,
|
||||
char *xpath,
|
||||
enum paging_status pagingstatus,
|
||||
uint32_t offset,
|
||||
uint32_t limit,
|
||||
cxobj **xp)
|
||||
|
|
@ -262,9 +264,9 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
|
|||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, clixon_plugin_name_get(cp));
|
||||
if ((fn2 = clixon_plugin_api_get(cp)->ca_statedata2) != NULL){
|
||||
if ((x = xml_new(XML_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
|
||||
if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
if (fn2(h, nsc, xpath, offset, limit, x) < 0){
|
||||
if (fn2(h, nsc, xpath, pagingstatus, offset, limit, 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));
|
||||
|
|
@ -272,7 +274,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
|
|||
}
|
||||
}
|
||||
else if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){
|
||||
if ((x = xml_new(XML_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
|
||||
if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
if (fn(h, nsc, xpath, x) < 0){
|
||||
if (clicon_errno < 0)
|
||||
|
|
@ -298,6 +300,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
|
|||
* @param[in] yspec Yang spec
|
||||
* @param[in] nsc Namespace context
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in] pagination List pagination
|
||||
* @param[in] offset Offset, for list pagination
|
||||
* @param[in] limit Limit, for list pagination
|
||||
* @param[in,out] xret State XML tree is merged with existing tree.
|
||||
|
|
@ -307,13 +310,14 @@ 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,
|
||||
uint32_t offset,
|
||||
uint32_t limit,
|
||||
cxobj **xret)
|
||||
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)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
|
|
@ -324,7 +328,8 @@ 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, offset, limit, &x)) < 0)
|
||||
if ((ret = clixon_plugin_statedata_one(cp, h, nsc, xpath, pagingstatus,
|
||||
offset, limit, &x)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if ((cberr = cbuf_new()) == NULL){
|
||||
|
|
@ -399,6 +404,64 @@ clixon_plugin_statedata_all(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Lock database status has changed status
|
||||
* @param[in] cp Plugin handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] db Database name (eg "running")
|
||||
* @param[in] lock Lock status: 0: unlocked, 1: locked
|
||||
* @param[in] id Session id (of locker/unlocker)
|
||||
* @retval -1 Fatal error
|
||||
* @retval 0 OK
|
||||
*/
|
||||
static int
|
||||
clixon_plugin_lockdb_one(clixon_plugin_t *cp,
|
||||
clicon_handle h,
|
||||
char *db,
|
||||
int lock,
|
||||
int id)
|
||||
{
|
||||
int retval = -1;
|
||||
plglockdb_t *fn; /* Plugin statedata fn */
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, clixon_plugin_name_get(cp));
|
||||
if ((fn = clixon_plugin_api_get(cp)->ca_lockdb) != NULL){
|
||||
if (fn(h, db, lock, id) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Lock database status has changed status
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] db Database name (eg "running")
|
||||
* @param[in] lock Lock status: 0: unlocked, 1: locked
|
||||
* @param[in] id Session id (of locker/unlocker)
|
||||
* @retval -1 Fatal error
|
||||
* @retval 0 OK
|
||||
*/
|
||||
int
|
||||
clixon_plugin_lockdb_all(clicon_handle h,
|
||||
char *db,
|
||||
int lock,
|
||||
int id
|
||||
)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
clixon_plugin_t *cp = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||
if (clixon_plugin_lockdb_one(cp, h, db, lock, id) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create and initialize a validate/commit transaction
|
||||
* @retval td New alloced transaction,
|
||||
* @retval NULL Error
|
||||
|
|
|
|||
|
|
@ -76,7 +76,10 @@ 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);
|
||||
int clixon_plugin_lockdb_all(clicon_handle h, char *db, int lock, int id);
|
||||
|
||||
transaction_data_t * transaction_new(void);
|
||||
int transaction_free(transaction_data_t *);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue