From ac5c133f4aef9d806cd1c800930c469f6cb5b764 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20Posp=C3=AD=C5=A1il?= Date: Thu, 11 Dec 2008 09:10:59 +0000 Subject: [PATCH] Querying API usage and examples (in C) --- org.glite.lb.doc/Makefile | 2 +- org.glite.lb.doc/examples/Makefile | 2 +- org.glite.lb.doc/examples/README | 1 + org.glite.lb.doc/examples/README.queries | 511 +++++++++++++++++++ org.glite.lb.doc/examples/cons_example1.c | 114 +++++ org.glite.lb.doc/examples/cons_example2.c | 129 +++++ org.glite.lb.doc/examples/cons_example3.c | 111 +++++ org.glite.lb.doc/src/consumer_api.tex | 795 +++++------------------------- 8 files changed, 982 insertions(+), 683 deletions(-) create mode 100644 org.glite.lb.doc/examples/README.queries create mode 100644 org.glite.lb.doc/examples/cons_example1.c create mode 100644 org.glite.lb.doc/examples/cons_example2.c create mode 100644 org.glite.lb.doc/examples/cons_example3.c diff --git a/org.glite.lb.doc/Makefile b/org.glite.lb.doc/Makefile index fbf1e8e..1a3363b 100644 --- a/org.glite.lb.doc/Makefile +++ b/org.glite.lb.doc/Makefile @@ -115,7 +115,7 @@ LBTP.pdf: ${COMMON} \ LBTP.tex \ LBTP-Abstract.tex \ LBTP-Introduction.tex \ - LBTP-IntegrationTests.tex \ + LBTP-IntegrationTests.tex \ LBTP-Tests.tex \ LBTP-PerfTests.tex \ LBTP-InterTests.tex diff --git a/org.glite.lb.doc/examples/Makefile b/org.glite.lb.doc/examples/Makefile index 62b09a8..8750461 100644 --- a/org.glite.lb.doc/examples/Makefile +++ b/org.glite.lb.doc/examples/Makefile @@ -37,7 +37,7 @@ LINK:=libtool --mode=link ${CC} ${LDFLAGS} LINKXX:=libtool --mode=link ${CXX} ${LDFLAGS} INSTALL:=libtool --mode=install install -EXAMPLES_SRC:=example1.c +EXAMPLES_SRC:=example1.c prod_example1.c cons_example1.c cons_example2.c cons_example3.c EXAMPLES:=${EXAMPLES_SRC:.c=} EXTRA_SRC:=util.c diff --git a/org.glite.lb.doc/examples/README b/org.glite.lb.doc/examples/README index 006bb32..7f85175 100644 --- a/org.glite.lb.doc/examples/README +++ b/org.glite.lb.doc/examples/README @@ -1 +1,2 @@ This directory contains source code of examples from LB Developer's Guide +To build these examples, set the GLITE_LOCATION variable and run make. diff --git a/org.glite.lb.doc/examples/README.queries b/org.glite.lb.doc/examples/README.queries new file mode 100644 index 0000000..214063f --- /dev/null +++ b/org.glite.lb.doc/examples/README.queries @@ -0,0 +1,511 @@ +In this file, you can find several examples how to set the query conditions. + +All user's jobs: +---------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[2]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +All user's jobs that are curently running: +------------------------------------------ + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[3]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[1].value.i = EDG_WLL_JOB_RUNNING; + jc[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +All user's jobs running at CE XYZ: +---------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[4]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[1].value.i = EDG_WLL_JOB_RUNNING; + jc[2].attr = EDG_WLL_QUERY_ATTR_DESTINATION; + jc[2].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2].value.c = "XYZ"; + jc[3].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +All user's jobs that have returned an exit code from 2 to 7: +------------------------------------------------------------ + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[4]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[1].value.i = EDG_WLL_JOB_DONE; + jc[2].attr = EDG_WLL_QUERY_ATTR_EXITCODE; + jc[2].op = EDG_WLL_QUERY_OP_WITHIN; + jc[2].value.i = 2; + jc[2].value2.i = 7; + jc[3].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +All user's jobs running at CE XXX or YYY: +----------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec *jc[4]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0] = (edg_wll_QueryRec *) malloc(2*sizeof(edg_wll_QueryRec)); + jc[0][0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0][0].value.c = NULL; + jc[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + jc[1] = (edg_wll_QueryRec *) malloc(2*sizeof(edg_wll_QueryRec)); + jc[1][0].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[1][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[1][0].value.i = EDG_WLL_JOB_RUNNING; + jc[1][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + jc[2] = (edg_wll_QueryRec *) malloc(3*sizeof(edg_wll_QueryRec)); + jc[2][0].attr = EDG_WLL_QUERY_ATTR_DESTINATION; + jc[2][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][0].value.c = "XXX"; + jc[2][1].attr = EDG_WLL_QUERY_ATTR_DESTINATION; + jc[2][1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][1].value.c = "YYY"; + jc[2][2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + jc[3] = NULL; + edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **)jc, 0, &jobsOut, &statesOut); + free(jc[0]); free(jc[1]); free(jc[2]); + ... + + +All user's jobs marked with the user tag 'color' and with its value 'red': +-------------------------------------------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[2]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].attr_id.tag = "color"; + jc[0].value.c = "red"; + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +All user's jobs marked with the user tag 'color' and with its value 'red' or 'green': +------------------------------------------------------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[1][3]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[0][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0][0].attr_id.tag = "color"; + jc[0][0].value.c = "red"; + jc[0][1].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[0][1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0][1].attr_id.tag = "color"; + jc[0][1].value.c = "green"; + jc[0][2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **)jc, 0, &jobsOut, &statesOut); + ... + + +All user's jobs marked with red color and using the 'xyz' algorithm: +-------------------------------------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[2]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].attr_id.tag = "color"; + jc[0].value.c = "red"; + jc[1].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[1].attr_id.tag = "algorithm"; + jc[1].value.c = "xyz"; + jc[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +All jobs that were submitted in the last 24 hours: +-------------------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[2]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_TIME; + jc[0].op = EDG_WLL_QUERY_OP_GREATER; + jc[0].attr_id.state = EDG_WLL_JOB_SUBMITTED; + jc[0].value.t.tv_sec = time_now - (24 * 60 * 60); + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +All jobs with a specified state within a particular time interval: +------------------------------------------------------------------ + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc[3]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_TIME; + jc[1].op = EDG_WLL_QUERY_OP_WITHIN; + jc[1].attr_id.state = EDG_WLL_JOB_SUBMITTED; + jc[1].value.t.tv_sec = time_now - (48 * 60 * 60); + jc[1].value2.t.tv_sec = time_now - (24 * 60 * 60); + jc[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); + ... + + +\label{ASQ} +Event queries and job queries are similar. +Obviously, the return type is different\Dash the \LB\ raw events. +There is one more input parameter +representing specific conditions on events (possibly empty) +in addition to conditions on jobs. +Some examples showing event queries +are considered in the following paragraph. + + +All events marking any user's job as 'red': +------------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_Event *eventsOut; + edg_wll_QueryRec jc[2]; + edg_wll_QueryRec ec[2]; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + ec[0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[0].attr_id.tag = "color"; + ec[0].value.c = "red"; + ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); + ... + + +All events marking red jobs as green: +------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_Event *eventsOut; + edg_wll_QueryRec jc[2]; + edg_wll_QueryRec ec[2]; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].attr_id.tag = "color"; + jc[0].value.c = "red"; + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + ec[0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[0].attr_id.tag = "color"; + ec[0].value.c = "green"; + ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); + ... + + +All user's jobs that were resubmitted: +-------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_Event *eventsOut; + edg_wll_QueryRec jc[2]; + edg_wll_QueryRec ec[2]; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; + ec[0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[0].value.i = EDG_WLL_EVENT_RESUBMISSION; + ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); + ... + + +All user's jobs which were resubmitted in the last 2 hours: +----------------------------------------------------------- + + #include + ... + edg_wll_Context ctx; + edg_wll_Event *eventsOut; + edg_wll_QueryRec jc[2]; + edg_wll_QueryRec ec[3]; + ... + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; + ec[0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[0].value.i = EDG_WLL_EVENT_RESUBMISSION; + ec[1].attr = EDG_WLL_QUERY_ATTR_TIME; + ec[1].op = EDG_WLL_QUERY_OP_GREATER; + ec[1].value.t.tv_sec = time_now - (2 * 60 * 60); + ec[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); + ... + + +Complex query: +-------------- +Task: which of my red jobs are heading to a destination +that already encountered problems executing red jobs? + +1. First we retrieve the information of red jobs failures. + + #include + ... + edg_wll_Context ctx; + edg_wll_QueryRec jc1[3],ec1[3]; + edg_wll_Event *failures; + + jc1[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc1[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc1[0].value.c = NULL; + jc1[1].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc1[1].attr_id.tag = "color"; + jc1[1].op = EDG_WLL_QUERY_OP_EQUAL; + jc1[1].value.c = "red"; + jc1[2].attr = EDG_WLL_QUERY_ATTR_DONECODE; + jc1[2].op = EDG_WLL_QUERY_OP_EQUAL; + jc1[2].value.i = EDG_WLL_DONE_FAILED; + jc1[3].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + ec1[0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; + ec1[0].op = EDG_WLL_QUERY_OP_EQUAL; + ec1[0].value.i = EDG_WLL_EVENT_DONE; + ec1[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + edg_wll_QueryEvents(ctx,jc1,ec1,&failures); + ... +\end{verbatim} + + +2. We loop over the job ID's extracted from the events returned +in the previous step, and retrieve their `Match' and `Done' events. + +Note: it is desirable to avoid repeated queries on the same job. + + ... + edg_wll_QueryRec *jc2[2],*ec2[2]; + char *last_job = strdup(""),*this_job,**failed_sites = NULL; + edg_wll_Event *match_done; + char **failed_sites; + int n, i, j; + ... + jc2[0][0].attr = EDG_WLL_QUERY_ATTR_JOBID; + jc2[0][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc2[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + jc2[1] = NULL; + ec2[0][0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; + ec2[0][0].op = EDG_WLL_QUERY_OP_EQUAL; + ec2[0][0].value.i = EDG_WLL_EVENT_MATCH; + ec2[0][1].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; + ec2[0][1].op = EDG_WLL_QUERY_OP_EQUAL; + ec2[0][1].value.i = EDG_WLL_EVENT_DONE; + ec2[0][2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec2[1] = NULL; + + n = 0; + for (i=0; failures[i].type; i++) { + this_job = edg_wlc_JobIdUnparse(failures[i].any.jobId); + if (strcmp(last_job,this_job)) { + free(last_job); + last_job = this_job; + jc2[0][0].value.j = failures[i].any.jobId; + edg_wll_QueryEventsExt(ctx,(const edg_wll_QueryRec **)jc2, + (const edg_wll_QueryRec **)ec2,&match_done); + for (j=0; match_done[j].type; j++) { + if (match_done[j].type == EDG_WLL_EVENT_MATCH && + match_done[j+1].type == EDG_WLL_EVENT_DONE && + match_done[j+1].done.status_code == EDG_WLL_DONE_FAILED) + { + failed_sites = realloc(failed_sites,(n+1)*sizeof *failed_sites); + failed_sites[n++] = strdup(match_done[j].match.dest_id); + } + edg_wll_FreeEvent(&match_done[j]); + } + } + else free(this_job); + edg_wll_FreeEvent(&failures[i]); + } + free(failures); + ... + + +3. Finally we can query the server for the jobs heading to one of the failing +sites. + + ... + edg_wll_QueryRec *jc3[3]; + edg_wlc_JobId *unlucky_jobs; + ... /* remove duplicates from failed_sites */ + + for (i=0; i + ... + edg_wll_Context ctx; + edg_wll_Event *eventsOut; + edg_wll_JobStat *statesOut; + edg_wlc_JobId *jobsOut; + edg_wll_QueryRec **jc; + edg_wll_QueryRec **ec; + ... + jc[0][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[0][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0][0].attr_id.tag = "color"; + jc[0][0].value.c = "red"; + jc[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + jc[2][0].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[2][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][0].value.i = EDG_WLL_JOB_SUBMITTED; + jc[2][1].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[2][1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][1].value.i = EDG_WLL_JOB_WAITING; + jc[2][2].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[2][2].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][2].value.i = EDG_WLL_JOB_READY; + jc[2][3].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[2][3].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][3].value.i = EDG_WLL_JOB_SCHEDULED; + jc[2][4].attr = EDG_WLL_QUERY_ATTR_UNDEF; + jc[3] = NULL; + edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **)jc, 0, &jobsOut, &statesOut); + ... + + ... + ec[0][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + ec[0][0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[0][0].attr_id.tag = "color"; + ec[0][0].value.c = "red"; + ec[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[1][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + ec[1][0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[1][0].attr_id.tag = "color"; + ec[1][0].value.c = "red"; + ec[1][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[2][0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; + ec[2][0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[2][0].value.i = EDG_WLL_EVENT_DONE; + ec[2][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[3] = NULL; + edg_wll_QueryEventsExt(ctx, (const edg_wll_QueryRec **)jc, (const edg_wll_QueryRec **)ec, &eventsOut); + ... + + diff --git a/org.glite.lb.doc/examples/cons_example1.c b/org.glite.lb.doc/examples/cons_example1.c new file mode 100644 index 0000000..4b955b1 --- /dev/null +++ b/org.glite.lb.doc/examples/cons_example1.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include + +/*headers*/ +#include "glite/jobid/cjobid.h" +#include "glite/lb/events.h" +#include "glite/lb/consumer.h" +/*end headers*/ + + +static struct option opts[] = { + {"help", 0, NULL, 'h'}, + {"sock", 1, NULL, 's'}, + {"jobid", 1, NULL, 'j'}, + {"user", 1, NULL, 'u'}, +}; + +static void usage(char *me) +{ + fprintf(stderr, "usage: %s [option]\n" + "\t-h, --help Shows this screen.\n" + "\t-s, --server LB Proxy socket.\n" + "\t-j, --jobid ID of requested job.\n" + "\t-u, --user User DN.\n" + , me); +} + + +int main(int argc, char *argv[]) +{ + char *server, *jobid_s, *user; + int opt, err = 0; + + server = code = jobid_s = name = value = NULL; + while ( (opt = getopt_long(argc, argv, "hs:j:u:c:n:v:", opts, NULL)) != EOF) + switch (opt) { + case 'h': usage(name); return 0; + case 's': server = strdup(optarg); break; + case 'j': jobid_s = strdup(optarg); break; + case 'u': user = strdup(optarg); break; + case '?': usage(name); return 1; + } + + if ( !jobid_s ) { fprintf(stderr, "JobId not given\n"); return 1; } + if ( !server ) { fprintf(stderr, "LB proxy socket not given\n"); return 1; } + + /*variables*/ + edg_wll_Context ctx; + edg_wll_QueryRec jc[4]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + /*end variables*/ + + if ( (errno = edg_wlc_JobIdParse(jobid_s, &jobid)) ) { perror(jobid_s); return 1; } + + /*context*/ + edg_wll_InitContext(&ctx); + + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, port); + /*end context*/ + + /*queryrec*/ + jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].value.c = NULL; + jc[1].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[1].value.i = EDG_WLL_JOB_RUNNING; + jc[2].attr = EDG_WLL_QUERY_ATTR_DESTINATION; + jc[2].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2].value.c = "XYZ"; + jc[3].attr = EDG_WLL_QUERY_ATTR_UNDEF; + /*end queryrec*/ + + /*query*/ + err = edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); //* \label{l:queryjobs} + if ( err == E2BIG ) { + fprintf(stderr,"Warning: only limited result returned!\n"); + return 0; + } elseif (err) { + char *et,*ed; + + edg_wll_Error(ctx,&et,&ed); + fprintf(stderr,"%s: edg_wll_QueryJobs(): %s (%s)\n",argv[0],et,ed); + + free(et); free(ed); + } + /*end query*/ + + /*printstates*/ + for (i = 0; statesOut[i].state; i++ ) { + printf("jobId : %s\n", edg_wlc_JobIdUnparse(statesOut[i].jobId)); + printf("state : %s\n\n", edg_wll_StatToString(statesOut[i].state)); + } + /*end printstates*/ + + if ( jobsOut ) { + for (i=0; jobsOut[i]; i++) edg_wlc_JobIdFree(jobsOut[i]); + free(jobsOut); + } + if ( statesOut ) { + for (i=0; statesOut[i].state; i++) edg_wll_FreeStatus(&statesOut[i]); + free(statesOut); + } + + edg_wll_FreeContext(ctx); + + return err; +} diff --git a/org.glite.lb.doc/examples/cons_example2.c b/org.glite.lb.doc/examples/cons_example2.c new file mode 100644 index 0000000..4a00e4e --- /dev/null +++ b/org.glite.lb.doc/examples/cons_example2.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include + +/*headers*/ +#include "glite/jobid/cjobid.h" +#include "glite/lb/events.h" +#include "glite/lb/consumer.h" +/*end headers*/ + + +static struct option opts[] = { + {"help", 0, NULL, 'h'}, + {"sock", 1, NULL, 's'}, + {"jobid", 1, NULL, 'j'}, + {"user", 1, NULL, 'u'}, +}; + +static void usage(char *me) +{ + fprintf(stderr, "usage: %s [option]\n" + "\t-h, --help Shows this screen.\n" + "\t-s, --server LB Proxy socket.\n" + "\t-j, --jobid ID of requested job.\n" + "\t-u, --user User DN.\n" + , me); +} + + +int main(int argc, char *argv[]) +{ + char *server, *jobid_s, *user; + int opt, err = 0; + + server = code = jobid_s = name = value = NULL; + while ( (opt = getopt_long(argc, argv, "hs:j:u:c:n:v:", opts, NULL)) != EOF) + switch (opt) { + case 'h': usage(name); return 0; + case 's': server = strdup(optarg); break; + case 'j': jobid_s = strdup(optarg); break; + case 'u': user = strdup(optarg); break; + case '?': usage(name); return 1; + } + + if ( !jobid_s ) { fprintf(stderr, "JobId not given\n"); return 1; } + if ( !server ) { fprintf(stderr, "LB proxy socket not given\n"); return 1; } + + /*variables*/ + edg_wll_Context ctx; + edg_wll_QueryRec *jc[4]; + edg_wll_JobStat *statesOut = NULL; + edg_wlc_JobId *jobsOut = NULL; + /*end variables*/ + + if ( (errno = edg_wlc_JobIdParse(jobid_s, &jobid)) ) { perror(jobid_s); return 1; } + + /*context*/ + edg_wll_InitContext(&ctx); + + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, port); + /*end context*/ + + /*queryrec*/ + jc[0] = (edg_wll_QueryRec *) malloc(2*sizeof(edg_wll_QueryRec)); + jc[0][0].attr = EDG_WLL_QUERY_ATTR_OWNER; + jc[0][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0][0].value.c = NULL; + jc[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + jc[1] = (edg_wll_QueryRec *) malloc(2*sizeof(edg_wll_QueryRec)); + jc[1][0].attr = EDG_WLL_QUERY_ATTR_STATUS; + jc[1][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[1][0].value.i = EDG_WLL_JOB_RUNNING; + jc[1][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + jc[2] = (edg_wll_QueryRec *) malloc(3*sizeof(edg_wll_QueryRec)); + jc[2][0].attr = EDG_WLL_QUERY_ATTR_DESTINATION; + jc[2][0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][0].value.c = "XXX"; + jc[2][1].attr = EDG_WLL_QUERY_ATTR_DESTINATION; + jc[2][1].op = EDG_WLL_QUERY_OP_EQUAL; + jc[2][1].value.c = "YYY"; + jc[2][2].attr = EDG_WLL_QUERY_ATTR_UNDEF; + + jc[3] = NULL; + /*end queryrec*/ + + /*query*/ + err = edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **)jc, + 0, &jobsOut, &statesOut); + /*end query*/ + + if ( err == E2BIG ) { + fprintf(stderr,"Warning: only limited result returned!\n"); + return 0; + } elseif (err) { + char *et,*ed; + + edg_wll_Error(ctx,&et,&ed); + fprintf(stderr,"%s: edg_wll_QueryJobs(): %s (%s)\n",argv[0],et,ed); + + free(et); free(ed); + } + + /*printstates*/ + for (i = 0; statesOut[i].state; i++ ) { + printf("jobId : %s\n", edg_wlc_JobIdUnparse(statesOut[i].jobId)); + printf("state : %s\n\n", edg_wll_StatToString(statesOut[i].state)); + } + /*end printstates*/ + + if ( jobsOut ) { + for (i=0; jobsOut[i]; i++) edg_wlc_JobIdFree(jobsOut[i]); + free(jobsOut); + } + if ( statesOut ) { + for (i=0; statesOut[i].state; i++) edg_wll_FreeStatus(&statesOut[i]); + free(statesOut); + } + free(jc[0]); free(jc[1]); free(jc[2]); + + edg_wll_FreeContext(ctx); + + return err; +} diff --git a/org.glite.lb.doc/examples/cons_example3.c b/org.glite.lb.doc/examples/cons_example3.c new file mode 100644 index 0000000..2d92d4a --- /dev/null +++ b/org.glite.lb.doc/examples/cons_example3.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include + +/*headers*/ +#include "glite/jobid/cjobid.h" +#include "glite/lb/events.h" +#include "glite/lb/consumer.h" +/*end headers*/ + + +static struct option opts[] = { + {"help", 0, NULL, 'h'}, + {"sock", 1, NULL, 's'}, + {"jobid", 1, NULL, 'j'}, + {"user", 1, NULL, 'u'}, +}; + +static void usage(char *me) +{ + fprintf(stderr, "usage: %s [option]\n" + "\t-h, --help Shows this screen.\n" + "\t-s, --server LB Proxy socket.\n" + "\t-j, --jobid ID of requested job.\n" + "\t-u, --user User DN.\n" + , me); +} + + +int main(int argc, char *argv[]) +{ + char *server, *jobid_s, *user; + int opt, err = 0; + + server = code = jobid_s = name = value = NULL; + while ( (opt = getopt_long(argc, argv, "hs:j:u:c:n:v:", opts, NULL)) != EOF) + switch (opt) { + case 'h': usage(name); return 0; + case 's': server = strdup(optarg); break; + case 'j': jobid_s = strdup(optarg); break; + case 'u': user = strdup(optarg); break; + case '?': usage(name); return 1; + } + + if ( !jobid_s ) { fprintf(stderr, "JobId not given\n"); return 1; } + if ( !server ) { fprintf(stderr, "LB proxy socket not given\n"); return 1; } + + /*variables*/ + edg_wll_Context ctx; + edg_wll_Event *eventsOut; + edg_wll_QueryRec jc[2]; + edg_wll_QueryRec ec[2]; + /*end variables*/ + + if ( (errno = edg_wlc_JobIdParse(jobid_s, &jobid)) ) { perror(jobid_s); return 1; } + + /*context*/ + edg_wll_InitContext(&ctx); + + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, server); + edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, port); + /*end context*/ + + /*queryrec*/ + jc[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + jc[0].op = EDG_WLL_QUERY_OP_EQUAL; + jc[0].attr_id.tag = "color"; + jc[0].value.c = "red"; + jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + ec[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; + ec[0].op = EDG_WLL_QUERY_OP_EQUAL; + ec[0].attr_id.tag = "color"; + ec[0].value.c = "green"; + ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; + /*end queryrec*/ + + /*query*/ + err = edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); + /*end query*/ + + if ( err == E2BIG ) { + fprintf(stderr,"Warning: only limited result returned!\n"); + return 0; + } elseif (err) { + char *et,*ed; + + edg_wll_Error(ctx,&et,&ed); + fprintf(stderr,"%s: edg_wll_QueryEvents(): %s (%s)\n",argv[0],et,ed); + + free(et); free(ed); + } + + /*printevents*/ + for (i = 0; eventsOut[i].type; i++ ) { + printf("jobId : %s\n", edg_wlc_JobIdUnparse(eventsOut[i].jobId)); + printf("event : %s\n\n", edg_wll_EventToString(eventsOut[i].type)); + } + /*end printevents*/ + + if ( eventsOut ) { + for (i=0; eventsOut[i]; i++) edg_wlc_JobIdFree(eventsOut[i]); + free(eventsOut); + } + + edg_wll_FreeContext(ctx); + + return err; +} diff --git a/org.glite.lb.doc/src/consumer_api.tex b/org.glite.lb.doc/src/consumer_api.tex index 8b444af..e5c7b30 100644 --- a/org.glite.lb.doc/src/consumer_api.tex +++ b/org.glite.lb.doc/src/consumer_api.tex @@ -87,7 +87,7 @@ Default value is \verb'EDG_WLL_QUERYRES_NONE'. \subsubsection{Header Files} -\begin{table}[h] +\begin{table}[h!] \begin{tabularx}{\textwidth}{>{\tt}lX} glite/lb/consumer.h & Prototypes for all query functions. \\ \end{tabularx} @@ -96,7 +96,7 @@ glite/lb/consumer.h & Prototypes for all query functions. \\ \subsubsection{Context Parameters} The table~\ref{t:ccontext} shows parameters relevant to the query API. -\begin{table}[h] +\begin{table}[h!] \begin{tabularx}{\textwidth}{lX} {\bf Name} & {\bf Description} \\ \hline @@ -136,11 +136,12 @@ errors results may still be returned. The authorization errors belong to unrecoverable, to obtain results the query must be repeated, possibly after correcting the failure condition the error indicated. -The \verb'E2BIG' error may fall into both categories depending on the -setting of context parameter \verb'EDG_WLL_PARAM_QUERY_RESULTS'. +Depending on the setting of context parameter +\verb'EDG_WLL_PARAM_QUERY_RESULTS', the \verb'E2BIG' error may fall into both +categories. -\subsubsection{Query condition encoding} +\subsubsection{Query Condition Encoding} The \LB query language is mapped into (one- or two-dimensional) array of attribute value assertions represented by \verb'edg_wll_QueryRec' structure: @@ -161,168 +162,78 @@ typedef struct _edg_wll_QueryRec { } edg_wll_QueryRec; \end{lstlisting} -\subsubsection{Job Queries} +% \TODO{pro prehlednost bych mozna pridal seznam vsech atributu na ktere se lze ptat} + +The table~\ref{t:cqueryattr} shows the most common query attributes. +For a complete list see \texttt{query\_rec.h}. + +\begin{table}[ht] +\begin{tabularx}{\textwidth}{lX} +{\bf Name} & {\bf Description} \\ +\hline +\lstinline'EDG_WLL_QUERY_ATTR_JOBID' & Job ID to query. \\ +\lstinline'EDG_WLL_QUERY_ATTR_OWNER' & Job owner. \\ +\lstinline'EDG_WLL_QUERY_ATTR_STATUS' & Current job status. \\ +\lstinline'EDG_WLL_QUERY_ATTR_LOCATION' & Where is the job processed. \\ +\lstinline'EDG_WLL_QUERY_ATTR_DESTINATION' & Destination CE. \\ +\lstinline'EDG_WLL_QUERY_ATTR_DONECODE' & Minor done status (OK,failed,cancelled). \\ +\lstinline'EDG_WLL_QUERY_ATTR_USERTAG' & User tag. \\ +\lstinline'EDG_WLL_QUERY_ATTR_JDL_ATTR' & Arbitrary JDL attribute. \\ +\lstinline'EDG_WLL_QUERY_ATTR_STATEENTERTIME' & When entered current status. \\ +\lstinline'EDG_WLL_QUERY_ATTR_LASTUPDATETIME' & Time of the last known event of the job. \\ +\end{tabularx} +\caption{Query record specific attributes.} +\label{t:cqueryattr} +\end{table} + +The table~\ref{t:cqueryop} shows all supported query operations. + +\begin{table}[ht] +\begin{tabularx}{\textwidth}{lX} +{\bf Name} & {\bf Description} \\ +\hline +\lstinline'EDG_WLL_QUERY_OP_EQUAL' & Attribute is equal to the operand value. \\ +\lstinline'EDG_WLL_QUERY_OP_LESS' & Attribute is grater than the operand value. \\ +\lstinline'EDG_WLL_QUERY_OP_GREATER' & Attribute is less than the operand value. \\ +\lstinline'EDG_WLL_QUERY_OP_WITHIN' & Attribute is in given interval. \\ +\lstinline'EDG_WLL_QUERY_OP_UNEQUAL' & Attribute is not equal to the operand value. \\ +\lstinline'EDG_WLL_QUERY_OP_CHANGED' & Attribute has changed from last check (supported only in notification matching). \\ +\end{tabularx} +\caption{Query record specific operations.} +\label{t:cqueryop} +\end{table} + + + +\subsubsection{Query Jobs Examples} The simplest case corresponds to the situation when an exact job ID is known and the only information requested is the job status. The job ID -format is described in~\cite{djra1.4}. -The following example shows -all the relevant structures and API calls to retrieve status information -about a job with the ID\\ -\texttt{https://lhun.ics.muni.cz:9000/OirOgeWh\_F9sfMZjnIPYhQ}. - -The first function call in this example initializes the \LB\ context\,---\,variable -\texttt{ctx}\,---\,which is necessary for later use. The most important part -of this code fragment is the \texttt{jc} variable setting. -Variable \texttt{jc} is a list of conditions terminated with the -\texttt{EDG\_WLL\_QUERY\_ATTR\_UNDEF} item. -In this example it contains the only data item\,---\,the job ID -(in its parsed form). - -If \texttt{edg\_wll\_QueryJobs()} is successful, returned results are available -in the \texttt{statesOut} variable. This variable contains an array of job states\,---\, -in this example state of a given job. - -The code also shows a~complete handling of returned errors as well as memory -management\,---\,deallocation of data that are not needed anymore. -\emph{For the sake of simplicity such code is not included in the -examples in the rest of this document.} - -%\partitle{All user's jobs} -\label{JQ-auj} - -\TODO{Update the example so that it is really working} - -The simple query example is a request for all user's jobs. Another -condition type, \\ -\texttt{EDG\_WLL\_QUERY\_ATTR\_OWNER}, is used in this case, with the -value field filled with a user name. You can found this example in client module, file \texttt{job\_status.c}. - -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[2]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -The value of the \texttt{attr} field which specifies job owner -could be set to \texttt{NULL} meaning the authenticated user. -Obtained results may differ according to the security level, e.g. with strong security -context only information about jobs of the specified user are returned -(in general info about all jobs a user is authorized to retrieve should be -returned). - -The query may return either a~list of job ID's or a~list of job states or both, -depending on the parameters \texttt{jobsOut} and \texttt{statesOut}. -If either is NULL the corresponding list is not retrieved. - -Developers should keep in mind that the output of such a query could be really huge. -\par - -The following examples demonstrates how \texttt{edg\_wll\_QueryJobs()} combines -the given conditions in a logical conjugation. - -%\partitle{Running jobs} -\label{JQ-rj} - -If all (user's) running jobs are to be retrieved the following code can -be used. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[3]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[1].op = EDG_WLL_QUERY_OP_EQUAL; - jc[1].value.i = EDG_WLL_JOB_RUNNING; - jc[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -This example combines previous example with a new criteria. There are used two different attributes - - \texttt{EDG\_WLL\_QUERY\_ATTR\_OWNER} and \texttt{EDG\_WLL\_QUERY\_ATTR\_STATE}. -\texttt{edg\_wll\_QueryJobs()} connects them in the logical conjunction. -Examples using logical conjunction and logical disjunction are shown in the Sect.~\ref{JQ-AO}. - -%\partitle{Jobs running at a given CE} -The following example gives description of all (user's) jobs running at CE XYZ. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[4]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[1].op = EDG_WLL_QUERY_OP_EQUAL; - jc[1].value.i = EDG_WLL_JOB_RUNNING; - jc[2].attr = EDG_WLL_QUERY_ATTR_DESTINATION; - jc[2].op = EDG_WLL_QUERY_OP_EQUAL; - jc[2].value.c = "XYZ"; - jc[3].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -In a case the job is not running the destination (attribute \texttt{EDG\_WLL\_QUERY\_ATTR\_DESTINATION}) -saves a CE name the job will be routed to. If location is needed use the \texttt{EDG\_WLL\_QUERY\_ATTR\_LOCATION} attribute. - - -%\partitle{The WITHIN operator} -The \texttt{EDG\_WLL\_QUERY\_OP\_WITHIN} operator can be used in any condition with numeric values. -The following example shows a query on all user's jobs that have returned -an exit code from 2 to 7. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[4]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[1].op = EDG_WLL_QUERY_OP_EQUAL; - jc[1].value.i = EDG_WLL_JOB_DONE; - jc[2].attr = EDG_WLL_QUERY_ATTR_EXITCODE; - jc[2].op = EDG_WLL_QUERY_OP_WITHIN; - jc[2].value.i = 2; - jc[2].value2.i = 7; - jc[3].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -The second attribute type (``state'') selects jobs in state ``done'' because it doesn't -make sense to query running jobs on their return code. -The last attribute (``exit code'') uses the WITHIN operator. The WITHIN operator accepts an -interval\,---\,the lower bound of the interval is stored in the \texttt{value} union and the -upper bound is stored in the \texttt{value2} union. - -%\partitle{Using AND, OR in query clauses} -\label{JQ-AO} +format is described in~\cite{djra1.4}. In \LBnew, it is also possible to +query all jobs belonging to a specified user, VO or RB. + +The following example shows how to retrieve the status information +about all user's jobs running at a specified CE. + +First we have to include neccessary headers: +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=headers-end\ headers]{cons_example1.c} + +Define and initialize variables: +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=variables-end\ variables]{cons_example1.c} + +Initialize context and set parameters: +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=context-end\ context]{cons_example1.c} + +Set the query record to \emph{all (user's) jobs running at CE 'XYZ'}: +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=queryrec-end\ queryrec]{cons_example1.c} + +Query jobs: +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=query-end\ query]{cons_example1.c} + +Now we can for example print the job states: +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=printstates-end\ printstates]{cons_example1.c} + + In many cases the basic logic using only conjunctions is not sufficient. For example, if you need all your jobs running at the destination XXX or at the destination YYY, the only way to do this with the \texttt{edg\_wll\_QueryJobs()} @@ -330,46 +241,17 @@ call is to call it twice. The \texttt{edg\_wll\_QueryJobsExt()} call allows to m such a~query in a single step. The function accepts an array of condition lists. Conditions within a~single list are OR-ed and the lists themselves are AND-ed. -%It is allowed to use only identical attributes in every standalone condition list. -%This is forced by an ``indexing'' definition, look at Sect.~\ref{ConsIndx} -%for further details. The next query example describes how to get all user's jobs running at -CE XXX or YYY. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec *jc[4]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0] = (edg_wll_QueryRec *) malloc(2*sizeof(edg_wll_QueryRec)); - jc[0][0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0][0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0][0].value.c = NULL; - jc[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - - jc[1] = (edg_wll_QueryRec *) malloc(2*sizeof(edg_wll_QueryRec)); - jc[1][0].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[1][0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[1][0].value.i = EDG_WLL_JOB_RUNNING; - jc[1][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - - jc[2] = (edg_wll_QueryRec *) malloc(3*sizeof(edg_wll_QueryRec)); - jc[2][0].attr = EDG_WLL_QUERY_ATTR_DESTINATION; - jc[2][0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[2][0].value.c = "XXX"; - jc[2][1].attr = EDG_WLL_QUERY_ATTR_DESTINATION; - jc[2][1].op = EDG_WLL_QUERY_OP_EQUAL; - jc[2][1].value.c = "YYY"; - jc[2][2].attr = EDG_WLL_QUERY_ATTR_UNDEF; - - jc[3] = NULL; - edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **)jc, 0, &jobsOut, &statesOut); - free(jc[0]); free(jc[1]); free(jc[2]); - ... -\end{verbatim} +CE 'XXX' or 'YYY'. + +We will need an array of three conditions (plus one last empty): + +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=variables-end\ variables]{cons_example2.c} + +The query condition is the following: + +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=queryrec-end\ queryrec]{cons_example2.c} As clearly seen, there are three lists supplied to \texttt{edg\_wll\_QueryJobsExt()}. The first list specifies the owner of the @@ -381,186 +263,24 @@ This query equals to the formula \texttt{(user=NULL) and (state=Running) and (dest='XXX' or dest='YYY')}. \end{quote} -%\partitle{User tags} -\label{JQ_ut} -\TODO{Is it really working?} -User tags can be used for marking (labelling) jobs. A user tag is -a pair of user defined \texttt{name} and \texttt{value}. - -\label{JQ_RedJobs} -For example, if all jobs marked with the user tag \texttt{color} and with its -value \texttt{red} should be retrieved, the following code can be used: -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[2]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].attr_id.tag = "color"; - jc[0].value.c = "red"; - jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} -The condition \texttt{EDG\_WLL\_QUERY\_ATTR\_USER\_TAG} in \texttt{jc[0]} -specifies that a user tag is set. Tag name is given in -\texttt{jc[0].attr\_id.tag} and the appropriate tag -value is given in \texttt{jc[0].value}. - - -Another example\,---\,jobs marked with red or green color: -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[1][3]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc[0][0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0][0].attr_id.tag = "color"; - jc[0][0].value.c = "red"; - jc[0][1].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc[0][1].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0][1].attr_id.tag = "color"; - jc[0][1].value.c = "green"; - jc[0][2].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **)jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -And the last one (with two user tags)\,---\,jobs marked with red color and using the 'xyz' algorithm: -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[2]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].attr_id.tag = "color"; - jc[0].value.c = "red"; - jc[1].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc[1].op = EDG_WLL_QUERY_OP_EQUAL; - jc[1].attr_id.tag = "algorithm"; - jc[1].value.c = "xyz"; - jc[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -Due to performance reasons -it is not possible to make query with two tags of different type in one -or-clause. -% fakt nevim, co tahle veta znamena. ljocha -%That means that user tags are composed of two variable components -%and user tag indices depend on tag names. - -%\partitle{Time attributes} - -%A time interval in which a particular state appears is attached to every job -%state. -Besides details on the job's current state the job status also carries -information when the job entered each of the distinguished states -(if ever). -This information is also queriable. - - -The following example shows how to get all jobs that were submitted in -the last 24 hours. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[2]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_TIME; - jc[0].op = EDG_WLL_QUERY_OP_GREATER; - jc[0].attr_id.state = EDG_WLL_JOB_SUBMITTED; - jc[0].value.t.tv_sec = time_now - (24 * 60 * 60); - jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -In this case, a record representing the necessary condition is quite -different. The \LB\ API allows to ask for jobs with a particular status at a -given time. When \LB\ server gets \texttt{EDG\_WLL\_QUERY\_ATTR\_TIME} -as a job condition, it checks \texttt{jc[0].attr\_id.state} for job state. -Note that \texttt{timenow} is a variable which contains current time in -seconds. - -It is easy to modify previous example and add another time boundary. It is then -possible to ask for all jobs with a specified state within a particular time -interval. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc[3]; - edg_wll_JobStat *statesOut = NULL; - edg_wlc_JobId *jobsOut = NULL; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_TIME; - jc[1].op = EDG_WLL_QUERY_OP_WITHIN; - jc[1].attr_id.state = EDG_WLL_JOB_SUBMITTED; - jc[1].value.t.tv_sec = time_now - (48 * 60 * 60); - jc[1].value2.t.tv_sec = time_now - (24 * 60 * 60); - jc[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryJobs(ctx, jc, 0, &jobsOut, &statesOut); - ... -\end{verbatim} - -\TODO{pro prehlednost bych mozna pridal seznam vsech atributu -na ktere se lze ptat} - -\subsubsection{Event queries and application specific queries} -\label{ASQ} -Event queries and job queries are similar. -Obviously, the return type is different\Dash the \LB\ raw events. -There is one more input parameter -representing specific conditions on events (possibly empty) -in addition to conditions on jobs. -Some examples showing event queries -are considered in the following paragraph. - - -%\partitle{All jobs marked as red} -\label{ASQ_allred} -This example shows how to select all user's jobs which were (at some time) -marked with the value red of user tag color. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_Event *eventsOut; - edg_wll_QueryRec jc[2]; - edg_wll_QueryRec ec[2]; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - ec[0].op = EDG_WLL_QUERY_OP_EQUAL; - ec[0].attr_id.tag = "color"; - ec[0].value.c = "red"; - ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); - ... -\end{verbatim} +To query the jobs, we simply call +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=query-end\ query]{cons_example2.c} + + + +\subsubsection{Query Events Examples} + +Event queries and job queries are similar. Obviously, the return type is +different \Dash the \LB\ raw events. There is one more input parameter +representing specific conditions on events (possibly empty) in addition to +conditions on jobs. + +The following example shows how to select all events (and therefore jobs) +marking red jobs (jobs that were marked red at some time in the past) as green. + +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=variables-end\ variables]{cons_example3.c} + +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=queryrec-end\ queryrec]{cons_example3.c} This example uses \texttt{edg\_wll\_QueryEvents()} call. Two condition lists are given to \texttt{edg\_wll\_QueryEvents()} call. One represents job conditions and @@ -568,309 +288,22 @@ the second represents event conditions. These two lists are joined together with logical and (both condition lists have to be satisfied). This is necessary as events represent a state of a job in a particular moment and this changes in time. +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=query-end\ query]{cons_example3.c} + The \texttt{edg\_wll\_QueryEvents()} returns matched events and save them in the \texttt{eventsOut} variable. Required job IDs are stored in the edg\_wll\_Event structure. -Due to the need of ``historic'' information it's impossible to address -this type of query with calling the function \texttt{edg\_wll\_QueryJobs()}, raw events has to -be retrieved instead. The example above retrieves all events marking -any user's job as ``red''. By gathering the jobid's from those events one -gets a~list of such jobs, not regarding whether their ``color'' was -changed afterwards or not (unlike straightforward \texttt{edg\_wll\_QueryJobs()} -which considers the ``current color'' only). The same applies on all -subsequent examples using the user's marking. - -%\partitle{All red jobs at some time marked as green} -The next example shows how to select all jobs which are just now marked with -user tag color red, but at some time in the past they were marked as green. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_Event *eventsOut; - edg_wll_QueryRec jc[2]; - edg_wll_QueryRec ec[2]; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].attr_id.tag = "color"; - jc[0].value.c = "red"; - jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec[0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - ec[0].op = EDG_WLL_QUERY_OP_EQUAL; - ec[0].attr_id.tag = "color"; - ec[0].value.c = "green"; - ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); - ... -\end{verbatim} - -Jobs conditions selects all jobs with tag ``color = red'' (See example in paragraph -\ref{JQ_RedJobs}). Event conditions selects all jobs which were sometimes marked -as green\,---\,this is described in previous example \ref{ASQ_allred}. - -%\partitle{All resubmitted jobs} -The next example shows how to get all (your) resubmitted jobs. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_Event *eventsOut; - edg_wll_QueryRec jc[2]; - edg_wll_QueryRec ec[2]; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec[0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; - ec[0].op = EDG_WLL_QUERY_OP_EQUAL; - ec[0].value.i = EDG_WLL_EVENT_RESUBMISSION; - ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); - ... -\end{verbatim} - -%\partitle{Jobs resubmitted in the last two hours} -The next example shows how to get all user's jobs which were resubmitted in the last -2 hours. -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_Event *eventsOut; - edg_wll_QueryRec jc[2]; - edg_wll_QueryRec ec[3]; - ... - jc[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0].value.c = NULL; - jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec[0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; - ec[0].op = EDG_WLL_QUERY_OP_EQUAL; - ec[0].value.i = EDG_WLL_EVENT_RESUBMISSION; - ec[1].attr = EDG_WLL_QUERY_ATTR_TIME; - ec[1].op = EDG_WLL_QUERY_OP_GREATER; - ec[1].value.t.tv_sec = time_now - (2 * 60 * 60); - ec[2].attr = EDG_WLL_QUERY_ATTR_UNDEF; - edg_wll_QueryEvents(ctx, jc, ec, &eventsOut); - ... -\end{verbatim} - - -%\partitle{Complex query} -The last example illustrates the API usage on - a~meaningful but rather complex query ``which of my red jobs are heading -to a~destination that already encountered problems executing red jobs''. - -First we retrieve the information of red jobs failures. -This cannot be accomplished with a~job query because the job may -get resubmitted automatically to another computing element and terminate -successfully. Therefore we need to search for the ``historic'' -information\,---\,`Done' events with their minor status -equal to `Failed'. - -\begin{verbatim} - #include - ... - edg_wll_Context ctx; - edg_wll_QueryRec jc1[3],ec1[3]; - edg_wll_Event *failures; - - jc1[0].attr = EDG_WLL_QUERY_ATTR_OWNER; - jc1[0].op = EDG_WLL_QUERY_OP_EQUAL; - jc1[0].value.c = NULL; - jc1[1].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc1[1].attr_id.tag = "color"; - jc1[1].op = EDG_WLL_QUERY_OP_EQUAL; - jc1[1].value.c = "red"; - jc1[2].attr = EDG_WLL_QUERY_ATTR_DONECODE; - jc1[2].op = EDG_WLL_QUERY_OP_EQUAL; - jc1[2].value.i = EDG_WLL_DONE_FAILED; - jc1[3].attr = EDG_WLL_QUERY_ATTR_UNDEF; - - ec1[0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; - ec1[0].op = EDG_WLL_QUERY_OP_EQUAL; - ec1[0].value.i = EDG_WLL_EVENT_DONE; - ec1[1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - - edg_wll_QueryEvents(ctx,jc1,ec1,&failures); - ... -\end{verbatim} - -Unfortunately, the `Done' event itself does not contain a~complete -identification of the queue where the job was running. -This information is contained in the `Match' events. -Moreover, there may be more than one such events in the job's life cycle -as the job may have been resubmitted. -Therefore we loop over the job ID's extracted from the events returned -in the previous step, and retrieve their `Match' and `Done' events. -The \LB\ API returns sorted results therefore we can assume that `Done' -events immediately following a~`Match' belong to the same attempt to submit -the job\footnote{In reality events may get lost or delayed. -Therefore strict checking the Match-Done pairing would require analysis -of the hierarchical event sequence codes. -However, this falls beyond the scope of this document.}. - -Due to job resubmissions again -a~job may be represented several times in \verb'failures'. -Because of obvious performance reasons -it is desirable to avoid repeated queries on the same job. -On the other hand, we may rely on \LB\ queries returning data grouped -according to jobs. Therefore checking duplicities is easy. - -\begin{verbatim} - ... - edg_wll_QueryRec *jc2[2],*ec2[2]; - char *last_job = strdup(""),*this_job,**failed_sites = NULL; - edg_wll_Event *match_done; - char **failed_sites; - int n, i, j; - ... - jc2[0][0].attr = EDG_WLL_QUERY_ATTR_JOBID; - jc2[0][0].op = EDG_WLL_QUERY_OP_EQUAL; - jc2[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - jc2[1] = NULL; - ec2[0][0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; - ec2[0][0].op = EDG_WLL_QUERY_OP_EQUAL; - ec2[0][0].value.i = EDG_WLL_EVENT_MATCH; - ec2[0][1].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; - ec2[0][1].op = EDG_WLL_QUERY_OP_EQUAL; - ec2[0][1].value.i = EDG_WLL_EVENT_DONE; - ec2[0][2].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec2[1] = NULL; - - n = 0; - for (i=0; failures[i].type; i++) { - this_job = edg_wlc_JobIdUnparse(failures[i].any.jobId); - if (strcmp(last_job,this_job)) { - free(last_job); - last_job = this_job; - jc2[0][0].value.j = failures[i].any.jobId; - edg_wll_QueryEventsExt(ctx,(const edg_wll_QueryRec **)jc2, - (const edg_wll_QueryRec **)ec2,&match_done); - for (j=0; match_done[j].type; j++) { - if (match_done[j].type == EDG_WLL_EVENT_MATCH && - match_done[j+1].type == EDG_WLL_EVENT_DONE && - match_done[j+1].done.status_code == EDG_WLL_DONE_FAILED) - { - failed_sites = realloc(failed_sites,(n+1)*sizeof *failed_sites); - failed_sites[n++] = strdup(match_done[j].match.dest_id); - } - edg_wll_FreeEvent(&match_done[j]); - } - } - else free(this_job); - edg_wll_FreeEvent(&failures[i]); - } - free(failures); - ... -\end{verbatim} - -The API would allow to perform a~single query instead of the loop, -putting all the job ID's into a~list of OR-ed conditions. -However, as the query conditions are directly converted to a~SQL statement -we don't recommend more than approx. 10--20 atomic conditions per query. -This number can be easily exceeded in the case of this example. -On the other hand, queries containing a~``jobid equals'' clause are very -effective and the overhead of repeating them is not very high. - -Finally we can query the server for the jobs heading to one of the failing -sites. -A~job's destination is known starting from the `Ready' state, -and the query makes sense also in the `Scheduled' state (\ie\ the job reached -the LRMS queue but has not been started yet). - -\begin{verbatim} - ... - edg_wll_QueryRec *jc3[3]; - edg_wlc_JobId *unlucky_jobs; - ... /* remove duplicates from failed_sites */ - - for (i=0; i - ... - edg_wll_Context ctx; - edg_wll_Event *eventsOut; - edg_wll_JobStat *statesOut; - edg_wlc_JobId *jobsOut; - edg_wll_QueryRec **jc; - edg_wll_QueryRec **ec; - ... - jc[0][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - jc[0][0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[0][0].attr_id.tag = "color"; - jc[0][0].value.c = "red"; - jc[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - jc[2][0].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[2][0].op = EDG_WLL_QUERY_OP_EQUAL; - jc[2][0].value.i = EDG_WLL_JOB_SUBMITTED; - jc[2][1].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[2][1].op = EDG_WLL_QUERY_OP_EQUAL; - jc[2][1].value.i = EDG_WLL_JOB_WAITING; - jc[2][2].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[2][2].op = EDG_WLL_QUERY_OP_EQUAL; - jc[2][2].value.i = EDG_WLL_JOB_READY; - jc[2][3].attr = EDG_WLL_QUERY_ATTR_STATUS; - jc[2][3].op = EDG_WLL_QUERY_OP_EQUAL; - jc[2][3].value.i = EDG_WLL_JOB_SCHEDULED; - jc[2][4].attr = EDG_WLL_QUERY_ATTR_UNDEF; - jc[3] = NULL; - edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **)jc, 0, &jobsOut, &statesOut); - - ec[0][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - ec[0][0].op = EDG_WLL_QUERY_OP_EQUAL; - ec[0][0].attr_id.tag = "color"; - ec[0][0].value.c = "red"; - ec[0][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec[1][0].attr = EDG_WLL_QUERY_ATTR_USERTAG; - ec[1][0].op = EDG_WLL_QUERY_OP_EQUAL; - ec[1][0].attr_id.tag = "color"; - ec[1][0].value.c = "red"; - ec[1][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec[2][0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE; - ec[2][0].op = EDG_WLL_QUERY_OP_EQUAL; - ec[2][0].value.i = EDG_WLL_EVENT_DONE; - ec[2][1].attr = EDG_WLL_QUERY_ATTR_UNDEF; - ec[3] = NULL; - edg_wll_QueryEventsExt(ctx, (const edg_wll_QueryRec **)jc, (const edg_wll_QueryRec **)ec, &eventsOut); - ... -\end{verbatim} -\fi - -\TODO{pro prehlednost bych mozna pridal seznam vsech atributu -na ktere se lze ptat} +\lstinputlisting[title={\bf File: }\lstname,numbers=left,linerange=printevents-end\ printevents]{cons_example3.c} + +In a similar manor to \texttt{edg\_wll\_QueryJobsExt()}, there exists also \texttt{edg\_wll\_QueryEventsExt()} +that can be used to more complex queries related to events. See also \texttt{README.queries} for more examples. + + +Last \LB Querying API call is \texttt{edg\_wll\_JobLog()} that returns all events related to a single job. +In fact, it is a convenience wrapper around \texttt{edg\_wll\_QueryEvents()} and its usage is clearly +demonstrated in the client example \texttt{job\_log.c} (in the client module). + \subsection{C++ Language Binding} -- 1.8.2.3