import of old LBUG
authorJan Pospíšil <honik@ntc.zcu.cz>
Thu, 6 Dec 2007 14:58:38 +0000 (14:58 +0000)
committerJan Pospíšil <honik@ntc.zcu.cz>
Thu, 6 Dec 2007 14:58:38 +0000 (14:58 +0000)
org.glite.lb.doc/src/LBUG.tex [new file with mode: 0644]
org.glite.lb.doc/src/arch.tex [new file with mode: 0644]
org.glite.lb.doc/src/cmdln_interface.tex [new file with mode: 0644]
org.glite.lb.doc/src/consumer_api.tex [new file with mode: 0644]
org.glite.lb.doc/src/copyright.tex [new file with mode: 0644]
org.glite.lb.doc/src/log_usertag.tex [new file with mode: 0644]
org.glite.lb.doc/src/logging-arch-notif.pdf [new file with mode: 0644]
org.glite.lb.doc/src/security.tex [new file with mode: 0644]

diff --git a/org.glite.lb.doc/src/LBUG.tex b/org.glite.lb.doc/src/LBUG.tex
new file mode 100644 (file)
index 0000000..7f87bcf
--- /dev/null
@@ -0,0 +1,188 @@
+\documentclass{egee}
+\usepackage{doxygen}
+\usepackage{tabularx}
+
+\def\LB{L\&B}
+\def\eg{e.\,g.}
+\def\ie{i.\,e.}
+\def\Dash{\,---\,\penalty-1000}
+\def\todo#1{\par\textbf{TODO:} #1\par}
+
+\title{Logging and Bookkeeping}
+\Subtitle{User's Guide}
+\author{CESNET EGEE II JRA1 team}
+\DocIdentifier{EGEE-II....}
+\Date{\today}
+\Activity{JRA1: Middleware Engineering and Integration}
+\DocStatus{DRAFT}
+\Dissemination{PUBLIC}
+\DocumentLink{http://...}
+
+\Abstract{
+This user's guide explains how to use the Logging and Bookkeeping (\LB) service. 
+The service architecture is described briefly. 
+Examples on using \LB\ event logging command to log a~user tag and change job ACL are given,
+as well as \LB\ query and notification API use cases.
+% The reference section contains complete description of both the logging command and the API's.
+}
+
+\begin{document}
+
+\input{frontmatter}
+\newpage
+\tableofcontents
+\newpage
+
+\section{Introduction}
+%This Section should give a brief summary of what the service described
+%is supposed to achieve and how it fits into the overall
+%architecture. It should contain subsections on the service internal
+%architecture and its relations to other services. 
+
+The Logging and Bookkeeping (\LB) service tracks jobs managed by 
+the gLite WMS (workload management system).
+It gathers events from various WMS components in a~reliable way
+and processes them in order to give a~higher level view, the
+\emph{status of job}.
+
+Virtually all the important
+data are fed to \LB\ internally from various gLite middleware
+components, transparently from the user's point of view.
+On the contrary, \LB\ provides public interfaces for querying the job
+information synchronously as well as registering for asynchronous
+notifications.
+API's for this functionality are described in this document in detail.
+
+
+\subsection{Service Architecture}
+\input{arch}
+
+
+\subsection{Security and Access Control}
+\input{security}
+
+
+\subsection{Interactions with other Services}
+\input{interaction}
+
+
+\newpage
+\section{Quickstart Guide}
+% The quickstart guide should explain in simple terms and with examples
+% how a user is supposed to achieve the most common usecases. E.g. how
+% to submit and cancel a job, how to receive a job's output. How to
+% create a grid file, move it around, locate it, and delete it. How to
+% monitor the progress on an application etc. 
+
+\subsection{Command-Line Tools}
+This section describes usage of event-logging \LB\ command in the two
+cases which are ment for the end-user: adding a~user description (tag)
+to a~job, and changing a~job access control list.
+
+\subsubsection{Logging a UserTag event}
+\label{log_usertag}
+\input{log_usertag}
+
+\subsubsection{Changing Job Access Control List}
+\label{change_acl}
+\input{change_acl}
+
+
+%% \subsection{\LB Producer API}
+%% \todo{honik}
+%% This API is not public at the moment, it may change later.
+%% \input{producer_api}
+
+
+\subsection{\LB\ Querying API}
+%\todo{valtri}
+\input{consumer_api}
+
+
+\subsection{\LB\ Notification API}
+\input{notification_api}
+
+
+\newpage
+\section{Reference Guide}
+
+%The reference guide should contain detailed descriptions of all
+%provided CLIs and APIs. There should be two subsections for those. 
+
+\subsection{Command-Line Interfaces}
+\label{cmdln_interface} 
+\input{cmdln_interface}
+
+
+\newpage
+
+\subsection{\LB\ Web Service Interface}
+
+The \LB\ web service interface currently reflects the functionality of legacy
+\LB\ query API (Sect.~\ref{query-C}). 
+
+The following sections describe the operations defined in the \LB\ WSDL
+file as well as its custom types.
+
+For the sake of readability this documentation does not follow the structure
+of WSDL strictly, avoiding to duplicate information which is already present
+here.
+Conseqently, the SOAP messages are not documented, for example, as they
+are derived from operation inputs and outputs mechanically.
+The same holds for types: \eg\ we do not document defined elements 
+which correspond 1:1 to types but are required due to the literal SOAP
+encoding.
+
+For exact definition of the operations and types see the WSDL file.
+
+
+{
+\def\chapter#1{}
+\def\section#1{\subsubsection{#1}}
+\def\subsection#1{\par\textbf{#1}\par}
+
+\let\odesc=\description
+\let\oedesc=\enddescription
+\renewenvironment{description}{\odesc\itemindent=1em
+\listparindent=2em
+}{\oedesc}
+%\renewenvironment{description}{\list{}{\labelwidth 5cm\leftmargin 5cm}}
+%{\endlist}
+
+\let\null=\relax
+%\input LB-ug
+}
+
+
+\newpage
+\section{Known Problems and Caveats}
+\input{caveats}
+
+
+\begin{thebibliography}1
+\bibitem[R1]{lbapi}\emph{\LB\ API Reference}, DataGrid-01-TED-0139.
+\bibitem[R2]{lbarch}\emph{\LB\ Architecture release 2}, DataGrid-01-TED-0141.
+\bibitem[R3]{WMS} G.Avellino at al., \emph{The DataGrid Workload Management System: Challenges and Results}, Journal of Grid Computing, ISSN: 1570-7873, 2005, accepted.
+\end{thebibliography}
+
+\clearpage
+
+\appendix
+
+\section{Component and Interaction Diagrams}
+% \todo{nekdy priste}
+% To help understanding the service a set of component and interaction
+% diagrams might help. This section is not mandatory. 
+
+
+\begin{figure}[h]
+\centering
+\includegraphics[width=.8\hsize]{logging-arch-notif}
+\caption{Overview of the \LB\ architecture}
+\label{fig-arch}
+\end{figure}
+
+
+
+
+\end{document}
diff --git a/org.glite.lb.doc/src/arch.tex b/org.glite.lb.doc/src/arch.tex
new file mode 100644 (file)
index 0000000..afd752d
--- /dev/null
@@ -0,0 +1,114 @@
+Within the gLite WMS, upon creation
+ each job is assigned a~unique, virtually non-recyclable
+\emph{job identifier} (JobId) in an~URL form.
+The server part of the URL designates the \emph{bookkeeping server} which
+gathers and provides information on the job for its whole life.
+
+High level view on the \LB\ architecture is shown in Fig.~\ref{fig-arch}
+on page~\pageref{fig-arch}.
+
+\LB\ tracks jobs in terms of \emph{events} (\eg\ \emph{Transfer} from a~WMS
+component to another one, \emph{Run} and \emph{Done} when the jobs starts
+and stops execution, \dots).
+Each event type carries its specific attributes.
+The entire architecture is specialized for this purpose and is job-centric\Dash
+any event is assigned to a~unique Grid job.
+
+\subsubsection{Event delivery and storage}
+The events are gathered from various WMS components by the
+\emph{\LB\ producer library}
+and passed on to the \emph{locallogger} daemon,
+running physically close to avoid
+any sort of network problems.
+The locallogger's task is storing the accepted event in a~local disk file.
+Once it's done, confirmation is sent back and the logging library call
+returns, reporting success.
+Consequently, logging calls have local, virtually non-blocking semantics.
+
+Further on, event delivery is managed by the \emph{interlogger} daemon.
+It takes the events from the locallogger (or the disk files on crash recovery),
+and repeatedly tries to deliver them to the destination
+bookkeeping server (known from the JobId) until it succeeds finally.
+Therefore the entire event delivery is highly reliable.
+However, in the standard mode described so far it is asynchronous
+(there is a~synchronous mode for special usage not discussed here)
+there is no direct way for the caller to see whether an event has been
+already delivered.
+Our experience shows that the semantics is suitable in the prevailing number
+of cases while being the most efficient in the erratic Grid environment.
+
+The bookkeeping server processes the incoming events
+to give a~higher level view
+on the job states (\eg\ \emph{Submitted, Running, Done}),
+each having an appropriate set of attributes again.
+\LB\ provides a~public interface (Sect.~\ref{query-C})
+to retrieve them via synchronous queries.
+
+Further on, upon each event delivery to the \LB\ server the new computed 
+job state is matched against the set of registered requests for notification.
+If some of them match, special events\Dash\emph{notifications} are generated
+and passed to a~modified 
+\emph{notification interlogger}.
+It takes over the notification from LB server, stores it into file and
+periodically tries to deliver it to the address where the corresponding
+notification client is listening.
+If the user changes this address (IP or port) 
+\LB\ server instructs the notification interlogger to change 
+the destination of possible pending notifications.
+
+\subsubsection{Queries}
+\label{arch-queries}
+One part of the \LB\ interface is the query API (Sect.~\ref{query-C}).
+Two types of queries are supported\Dash\emph{job queries} which return
+one or more jobs, including a~detailed description of their states,
+and \emph{event queries} returning the raw \LB\ events.
+In general, job queries are used to track normal life of jobs,
+event queries are used mostly for tracing abnormal behaviour. 
+
+Each query is formed of several conditions (\eg\ concrete jobid's,
+owner of jobs, particular job state etc.).
+The \LB\ library formats the conditions into a~query message, passes it to
+the server, and waits for the response which is passed to the user
+synchronously.
+
+\subsubsection{Notifications}
+\label{notification}
+On the contrary, the notification API (Sect.~\ref{notify-C}) allows
+the user to 
+register for notifications. These are delivered to the listening
+client asynchronously, when the particular event (a~change of job status
+typically) occurs.
+The main purpose of this \LB\ functionality is avoiding unnecessary load
+on the \LB\ server serving many repeated queries (polling) with the same
+result most of the time.
+
+Using a~notification client (program that uses LB client
+API to handle notifications) the user registers with a~\LB\ server
+to receive notifications. 
+She  must specify conditions under which the
+notification is sent. These conditions are a~subset of the conditions
+available for synchronous queries (Sect.~\ref{arch-queries}).
+Currently due to implementation constraints, one
+or more jobid's are required among the conditions and only
+a~single occurrence of a~specific attribute is allowed. The registration is 
+sent to the \LB\ server in the same way as synchronous queries,
+and stored there.
+In response, the server generates a~unique notification ID which is used
+by the user to refer to this notification further on.
+The user may
+change conditions which trigger notification, prolong validity of
+the registration, remove the registration from LB server,
+or even change the destination of notifications, \ie\ the address where
+a~client listens for notifications.
+
+The registration is soft-state; it exists only for limited amount of time. The
+validity is returned by LB server together with notification ID.
+
+While the registration is valid, 
+the user may stop the notification client and launch another, even
+on a~different machine.
+Notifications generated during the time when there was no client listening
+for them are kept by the notification interlogger.
+Once a~new listening address is announced to the
+server, the pending notifications are delivered. 
+
diff --git a/org.glite.lb.doc/src/cmdln_interface.tex b/org.glite.lb.doc/src/cmdln_interface.tex
new file mode 100644 (file)
index 0000000..ddf2a55
--- /dev/null
@@ -0,0 +1,54 @@
+Besides the API's \LB\ offers its users a simple command-line interface for
+logging events. The command glite-lb-logevent is used for this purpose. However, it
+is intended for internal WMS debugging tests in the first place and should not
+be used for common event logging because of possibility of confusing \LB\
+server job state automaton.
+
+The only legal user usage is for logging \verb'UserTag' and \verb'ChangeACL' events. The following description is therefore concentrating only on options dealing with these two events.
+
+Command usage is:
+
+\begin{verbatim}
+    glite-lb-logevent [-h] [-p] [-c seq_code] \
+        -j <dg_jobid> -s Application -e <event_name> [key=value ...]
+\end{verbatim}
+
+where
+
+\begin{tabularx}{\textwidth}{lX}
+\texttt{  -h  -{}-help} &           this help message\\
+\texttt{  -p  -{}-priority} &       send a priority event\\
+\texttt{  -c  -{}-sequence} &       event sequence code\\
+\texttt{  -j  -{}-jobid} &          JobId\\
+\texttt{  -e  -{}-event} &           select event type (see -e help)\\
+\end{tabularx}
+
+\medskip
+
+Each event specified after \verb'-e' option has different sub-options enabling to set event specific values.
+
+Sub-options usable with \verb'UserTag' event are:
+
+
+\begin{tabularx}{\textwidth}{lX}
+\texttt{      -{}-name}  &          tag name\\
+\texttt{      -{}-value} &          tag value\\
+\end{tabularx}
+
+\medskip
+
+Sub-options usable with \verb'ChangeACL' event are:
+
+\begin{tabularx}{\textwidth}{lX}
+\texttt{      -{}-operation} &       operation requested to perform with ACL (add, remove)\\
+\texttt{      -{}-permission} &      ACL permission to change (currently only READ)\\
+\texttt{      -{}-permission\_type} & type of permission requested (0 = 'allow', 1 = 'deny')\\
+\texttt{      -{}-user\_id} &         DN or VOMS parameter (in format VO:group)\\
+\texttt{      -{}-user\_id\_type} &    type of information given in \verb'user_id' (DN or VOMS)\\
+\end{tabularx}
+
+\bigskip
+
+To be able to use this command several environmental variables must be set properly. User must specify where the event should be sent. This is address and port of glite-lb-logd daemon. It is done using environmental variable \verb'EDG_WL_LOG_DESTINATION' in a form \verb'address:port'.
+
+Because user is allowed to change ACL or add user tags only for her jobs, paths to valid X509 user credentials has to be set to authorise her. This is done using two environmental variables \verb'EDG_WL_X509_KEY' and \verb'EDG_WL_X509_CERT' in a form \verb'path_to_cred'.
diff --git a/org.glite.lb.doc/src/consumer_api.tex b/org.glite.lb.doc/src/consumer_api.tex
new file mode 100644 (file)
index 0000000..e1d7034
--- /dev/null
@@ -0,0 +1,801 @@
+\def\partitle#1{\par{\textbf{#1}}\par}
+
+\label{ConsOview}
+This section describes the aspects of principal use of the \LB\ consumer API.
+It begins with the simplest examples how to query the bookkeeping
+service, continues with various selection criteria and their combinations, and
+through queries on user tags and timestamps it concludes with the discussion of
+application specific queries.
+
+The document is intended for users interested in the \LB\
+consumer API or those interested in better understanding of the \LB\ service 
+capabilities.
+
+In the presented examples only the C \LB\ API (Sect.~\ref{query-C}) is considered.
+The C++ API (Sect.~\ref{query-CPP})  covers the same functionality.
+
+\subsubsection{Returned results}
+
+\LB\ server returns errors which are classified as hard and soft errors.
+The main difference between these categories is that in the case of soft
+errors results may still be returned.
+The authentication errors belong to
+``soft error'' sort. Hard errors are typically all unrecoverable errors like ENOMEM.
+
+When the item count returned by \LB\ server exceeds the defined limits, the E2BIG error occur.
+There are two limits\,---\,the server and the user limit. The user defined limit may be set in
+the context at the client side in the following way:
+\begin{verbatim}
+  #include <glite/lb/context.h>
+  ...
+  edg_wll_Context     ctx;    
+
+  edg_wll_InitContext(&ctx);
+  edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_JOBS_LIMIT, 10);
+  edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_EVENTS_LIMIT, 20);
+  edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_RESULTS, 30);
+  ...
+  edg_wll_FreeContext(ctx);
+\end{verbatim}
+This code sets the user query limits to the given maximal count of items.
+
+The E2BIG error may fall into both categories depending on the setting of
+another context parameter, EDG\_WLL\_PARAM\_QUERY\_RESULTS.
+It may take the following values:
+
+%The E2BIG error can be classified as hard or soft error too because this error can be affected
+%by one more parameter which can make this error hard or soft. This parameter can be set like this:\\
+%\texttt{edg\_wll\_SetParam(ctx, EDG\_WLL\_PARAM\_QUERY\_RESULTS, EDG\_WLL\_QUERYRES\_ALL);}
+%and possible values follows:
+\begin{itemize}
+       \item{EDG\_WLL\_QUERYRES\_NONE}\,---\,No results are returned.
+       In this case an E2BIG error acts like a hard error.
+       \item{EDG\_WLL\_QUERYRES\_LIMITED}\,---\,A result contains at most ``limit'' item count.
+       In this case an E2BIG error acts like a soft error.
+       \item{EDG\_WLL\_QUERYRES\_ALL}\,---\,All results are returned and limits has no effect.
+       This option is available only in special cases such as ``user jobs query'' and 
+       the ``job status query''. Otherwise the EINVAL error is returned.
+\end{itemize}
+Default value is EDG\_WLL\_QUERYRES\_NONE.
+
+
+\subsubsection{Job queries}
+
+\partitle{Job status}
+\label{JS}
+
+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{lbapi}.
+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}.
+
+\begin{verbatim}
+  #include <glite/lb/consumer.h>
+  ...
+  edg_wll_Context     ctx;    
+  edg_wll_JobStat    *statesOut = NULL;
+  edg_wll_QueryRec    jc[2];
+  ...
+  edg_wll_InitContext(&ctx);
+  ...
+  jc[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
+  jc[0].op = EDG_WLL_QUERY_OP_EQUAL;
+  if ( edg_wlc_JobIdParse(
+    "https://lhun.ics.muni.cz:9000/OirOgeWh_F9sfMZjnIPYhQ",
+     &jc[0].value.j) )
+  {
+     edg_wll_FreeContext(ctx);
+     exit(1);
+  }
+  jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+  if (edg_wll_QueryJobs(ctx, jc, 0, NULL, &statesOut)) {
+    char    *err_text,*err_desc;
+
+    edg_wll_Error(ctx,&err_text,&err_desc);
+    fprintf(stderr,"QueryJobs: %s (%s)\n",err_text,err_desc);
+    free(err_text);
+    free(err_desc);
+  }
+  else {
+    ...        /* process the returned data */
+    edg_wll_FreeStatus(statesOut);
+    free(statesOut);
+  }
+  edg_wlc_JobIdFree(jc[0].value.j);
+  edg_wll_FreeContext(ctx);
+\end{verbatim}
+
+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}
+
+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 <glite/lb/consumer.h>
+  ...
+  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.
+
+\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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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}
+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()}
+call is to call it twice. The \texttt{edg\_wll\_QueryJobsExt()} call allows to make
+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 <glite/lb/consumer.h>
+  ...
+  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}
+
+As clearly seen, there are three lists supplied to
+\texttt{edg\_wll\_QueryJobsExt()}. The first list specifies the owner of the
+job, the second list provides the required status (\texttt{Running}) and
+the last list specifies the two destinations. 
+The list of lists is terminated with \texttt{NULL}.
+This query equals to the formula 
+\begin{quote}
+\texttt{(user=NULL) and (state=Running) and (dest='XXX' or dest='YYY')}.
+\end{quote}
+
+\partitle{User tags}
+\label{JQ_ut}
+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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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}
+
+
+\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 <glite/lb/consumer.h>
+  ...
+  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}
+
+This example uses \texttt{edg\_wll\_QueryEvents()} call. Two condition lists are
+given to \texttt{edg\_wll\_QueryEvents()} call. One represents job conditions and
+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.
+
+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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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 <glite/lb/consumer.h>
+  ...
+  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<n; i++) {
+    jc3[0][i].attr = EDG_WLL_QUERY_ATTR_DESTINATION;
+    jc3[0][i].op = EDG_WLL_QUERY_OP_EQUAL;
+    jc3[0][i].value.c = failed_sites[i];
+  }
+  jc3[0][i].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+
+  jc3[1][0].attr = EDG_WLL_QUERY_ATTR_STATUS;
+  jc3[1][0].op = EDG_WLL_QUERY_OP_EQUAL;
+  jc3[1][0].value.i = EDG_WLL_JOB_READY;
+  jc3[1][1].attr = EDG_WLL_QUERY_ATTR_STATUS;
+  jc3[1][1].op = EDG_WLL_QUERY_OP_EQUAL;
+  jc3[1][1].value.i = EDG_WLL_JOB_SCHEDULED;
+  jc3[1][2].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+
+  jc3[2] = NULL;
+  edg_wll_QueryJobsExt(ctx,(const edg_wll_QueryRec **)jc3,0,&unlucky_jobs,NULL);
+  ...
+\end{verbatim}
+
+See also complex example in client module, file \texttt{query\_ext.c}.
+
+\iffalse
+The last example deals with a more complex situation where too complex actual
+query must be
+split into two simpler queries and user must perform an intersection
+on the obtained results.
+We need to get all red jobs routed to destination X on which were already some 
+red jobs, but they have failed. 
+
+\begin{verbatim}
+  #include <glite/lb/consumer.h>
+  ...
+  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
diff --git a/org.glite.lb.doc/src/copyright.tex b/org.glite.lb.doc/src/copyright.tex
new file mode 100644 (file)
index 0000000..3c17886
--- /dev/null
@@ -0,0 +1,24 @@
+% Taken from:
+% https://twiki.cern.ch/twiki/bin/view/EGEE/EGEEgLiteSoftwareLicense
+%
+\vfill{}
+
+{\bf
+Copyright \copyright Members of the EGEE Collaboration. 2004.  See
+\href{http://www.eu-egee.org/partners/}{http://www.eu-egee.org/partners/} for
+details on the copyright holders.  
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License.  You may obtain a copy of the
+License at 
+
+\begin{center}
+\href{http://www.apache.org/licenses/LICENSE-2.0}{http://www.apache.org/licenses/LICENSE-2.0}
+\end{center}
+
+Unless required by applicable law or agreed to in writing, software distributed
+under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations under the License.
+}
+
diff --git a/org.glite.lb.doc/src/log_usertag.tex b/org.glite.lb.doc/src/log_usertag.tex
new file mode 100644 (file)
index 0000000..629b34e
--- /dev/null
@@ -0,0 +1,54 @@
+
+
+User tag is an arbitrary ``name=value'' pair with which the user can 
+assign additional information to a job. Further on, LB can be queried
+based also on values of user tags.
+% (see Sect.~\ref{tag-query}).
+
+In order to add user tag for a job a special event \verb+UserTag+ is used. This
+event can be logged by the job owner using the glite-lb-logevent command (see also
+sec.\ref{cmdln_interface}). Here we suppose the command is used from user's running
+ application because a correct setting of environment variables needed by 
+the command is assured.
+
+General template for adding user tag is as follows:
+
+\begin{verbatim}
+glite-lb-logevent -s Application -e UserTag    \
+        -j <job_id>                         \
+        -c <seq_code>                       \
+        --name <tag_name>                   \
+        --value <tag_value>
+\end{verbatim}
+
+where
+
+\begin{tabularx}{\textwidth}{lX}
+\verb'<job_id>'    & specifies the job to change \\
+\verb'<seq_code>'   & specifies the sequence code returned by previous call
+                       of verb 'glite-lb-logevent'\\
+\verb'<tag_name>'    & specifies the name of user tag\\
+\verb'<tag_value>' & specifies the value of user tag\\
+\end{tabularx}
+
+The user application is always executed from within a JobWrapper script (part of Workload Management System \cite{WMS}). The wrapper  sets the  appropriate \verb'JobId' in the environment variable \verb'GLITE_WMS_JOBID'. The user should pass this value to the -j option of glite-lb-logevent.  Similarly, the wrapper sets an initial value of the event sequence code in the environment variable \verb'GLITE_WMS_SEQUENCE_CODE'.
+
+If the user application calls glite-lb-logevent just once, it is sufficient to pass this value to the -c option.  However, if there are more  subsequent calls,  the  user is responsible for capturing an updated sequence code from the stdout of glite-lb-logevent and using it in subsequent calls.  The \LB\ design requires the sequence codes in  order  to  be able to sort events correctly while not relying on strictly synchronized clocks.  
+
+The example bellow is a job consisting of 100 phases.  A user tag phase is used to log the phase  currently  being executed.  Subsequently, the user may monitor execution of the job phases as a part of the job status returned by \LB.
+
+\begin{verbatim}
+  #!/bin/sh
+
+  for p in `seq 1 100`; do
+
+  # log the UserTag event
+  GLITE_WMS_SEQUENCE_CODE=`glite-lb-logevent -s Application
+    -e UserTag
+    -j $GLITE_WMS_JOBID -c $GLITE_WMS_SEQUENCE_CODE
+    --name=phase --value=$p`
+
+  # do the actual computation here
+  done
+\end{verbatim}
+
diff --git a/org.glite.lb.doc/src/logging-arch-notif.pdf b/org.glite.lb.doc/src/logging-arch-notif.pdf
new file mode 100644 (file)
index 0000000..09a3920
Binary files /dev/null and b/org.glite.lb.doc/src/logging-arch-notif.pdf differ
diff --git a/org.glite.lb.doc/src/security.tex b/org.glite.lb.doc/src/security.tex
new file mode 100644 (file)
index 0000000..4178f7a
--- /dev/null
@@ -0,0 +1,56 @@
+The \LB\ infrastructure ensures high level of security for information it
+processes. All the \LB\ components communicate solely over authenticated
+connections and users who query the \LB\ server also must authenticate properly
+using their PKI certificates. All messages sent over the network are encrypted
+and their content is not accessible to unauthorized people.
+
+By default, information about a job stored in the \LB\ server is only available
+to the user who submitted the job, i.e. the job owner.  Besides this default
+functionality, the \LB\ server also allows the job owner to share job
+information with another users. Each job can be assigned an access control list
+(ACL) that specifies another users who are also allowed to access the job
+information. The management of ACL's is entirely under control of the job owner
+so she can modify the ACL arbitrarily, specifying the set of users who have
+access to the job information. The users in the ACL's can be specified using
+either the subject names from their X.509 certificates or names of VOMS groups.
+
+Current ACL for a job is returned as part of the job status information
+returned by the \verb'glite-job-status' command. The commands output ACL's in
+the original XML format as specified by GACL/GridSite. 
+
+Example of an ACL:
+\begin{verbatim}
+<?xml version="1.0"?><gacl version="0.0.1">
+   <entry>
+      <voms-cred><vo>VOCE</vo><group>/VOCE</group></voms-cred>
+      <allow><read/></allow>
+   </entry>
+   <entry>
+      <person><dn>/O=CESNET/O=Masaryk University/CN=Daniel Kouril</dn></person>
+      <deny><read/></deny>
+   </entry>
+</gacl>
+\end{verbatim}
+
+This ACL allows access to all people in the VOMS group /VOCE in virtual
+organization VOCE, but denies access to user Daniel Kouril (even if he was a
+member of the /VOCE group).
+
+The job owner herself is not specified in the ACL as she is always allowed to
+access the information regardless the content of the job ACL.
+
+An ACL for a job can be changed using the \verb'glite-lb-logevent' command-line
+program, see section~\ref{change_acl}.
+
+%provided in the example subdirectory. In order to use change\_acl, the \LB\
+%daemons locallogger and interlogger must be running. The usage of the command
+%is as follows:
+%
+%\LB\ server configuration
+%In order to support the VOMS groups in the ACL's,
+%glite_lb_bkserverd must be able to verify client's VOMS proxy certificate using
+%a trusted VOMS service certificate stored on a local disk. Default directory
+%with trusted VOMS certificates is /etc/grid-security/vomsdir, another location
+%can be specified using by either the -V option to glite_lb_bkserverd or setting
+%the VOMS_CERT_DIR environment variable.
+