- bug#19533
authorJan Pospíšil <honik@ntc.zcu.cz>
Sun, 3 Sep 2006 16:21:20 +0000 (16:21 +0000)
committerJan Pospíšil <honik@ntc.zcu.cz>
Sun, 3 Sep 2006 16:21:20 +0000 (16:21 +0000)
- cleanup

org.glite.lb.server/src/jobstat_supp.c
org.glite.lb.server/src/lb_plugin.c

index 54351ac..2261dcf 100644 (file)
@@ -17,8 +17,8 @@
 
 #include "store.h"
 #include "index.h"
-#include "jobstat.h"
 #include "lbs_db.h"
+#include "jobstat.h"
 #include "get_events.h"
 
 
@@ -760,8 +760,8 @@ int edg_wll_compare_seq(const char *a, const char *b)
 
 static int compare_events_by_seq(const void *a, const void *b)
 {
-        const edg_wll_Event *e = (edg_wll_Event *)a;
-        const edg_wll_Event *f = (edg_wll_Event *)b;
+        const edg_wll_Event *e = (edg_wll_Event *) a;
+        const edg_wll_Event *f = (edg_wll_Event *) b;
        int ret;
 
        ret = edg_wll_compare_seq(e->any.seqcode, f->any.seqcode);
@@ -774,13 +774,33 @@ static int compare_events_by_seq(const void *a, const void *b)
        return 0;
 }
 
+static int compare_pevents_by_seq(const void *a, const void *b)
+{
+        const edg_wll_Event **e = (edg_wll_Event **) a;
+        const edg_wll_Event **f = (edg_wll_Event **) b;
+       return compare_events_by_seq(*e,*f);
+}
+
 void edg_wll_SortEvents(edg_wll_Event *e)
 {
        int     n;
 
        if (!e) return;
        for (n=0; e[n].type; n++);
-       qsort(e,n,sizeof *e,compare_events_by_seq);
+       qsort(e,n,sizeof(*e),compare_events_by_seq);
+}
+
+void edg_wll_SortPEvents(edg_wll_Event **e)
+{
+       edg_wll_Event **p;
+       int     n;
+
+       if (!e) return;
+       p = e;
+       for (n=0; *p; n++) {
+               p++;
+       }
+       qsort(e,n,sizeof(*e),compare_pevents_by_seq);
 }
 
 
index b98f706..106554e 100644 (file)
 
 #include "glite/lb/context.h"
 #include "glite/lb/jobstat.h"
-
 #include "glite/lb/events.h"
 #include "glite/lb/events_parse.h"
-
 #include "glite/lb/trio.h"
 
 #include "jobstat.h"
+#include "get_events.h"
 
 #include "glite/jp/types.h"
 #include "glite/jp/context.h"
 #include "jp_job_attrs.h"
 
 #define INITIAL_NUMBER_EVENTS 100
+#define INITIAL_NUMBER_STATES EDG_WLL_NUMBER_OF_STATCODES
 #define LB_PLUGIN_NAMESPACE "urn:org.glite.lb"
 
 typedef struct _lb_buffer_t {
-       char *buf;
-       size_t pos, size;
-       off_t offset;
+       char                    *buf;
+       size_t                  pos, size;
+       off_t                   offset;
 } lb_buffer_t;
 
+typedef struct _lb_historyStatus {
+       edg_wll_JobStatCode     state;
+       struct timeval          timestamp;
+       char                    *reason;
+} lb_historyStatus;
+
 typedef struct _lb_handle {
-       edg_wll_Event   **events;
-       edg_wll_JobStat status;
+       edg_wll_Event           **events;
+       edg_wll_JobStat         status;
+       lb_historyStatus        **fullStatusHistory, **lastStatusHistory;
 } lb_handle;
 
 #define check_strdup(s) ((s) ? strdup(s) : NULL)
 
 extern int processEvent(intJobStat *, edg_wll_Event *, int, int, char **);
 
-static int lb_query(void *fpctx,void *handle,const char * attr,glite_jp_attrval_t **attrval);
-static int lb_open(void *,void *, const char *uri, void **);
-static int lb_close(void *,void *);
-static int lb_status(edg_wll_Event **event, edg_wll_JobStat *status);
-static int read_line(glite_jp_context_t  ctx, void *handle, lb_buffer_t *buffer, char **line);
-
+static int lb_query(void *fpctx, void *handle, const char *attr, glite_jp_attrval_t **attrval);
+static int lb_open(void *fpctx, void *bhandle, const char *uri, void **handle);
+static int lb_close(void *fpctx, void *handle);
+static int lb_status(void *handle);
+static int read_line(glite_jp_context_t ctx, void *handle, lb_buffer_t *buffer, char **line);
 
 static int lb_dummy(void *fpctx, void *handle, int oper, ...) {
        puts("lb_dummy() - generic call not used; for testing purposes only...");
@@ -133,7 +139,7 @@ static int lb_open(void *fpctx, void *bhandle, const char *uri, void **handle) {
                                h->events = realloc(h->events, maxnevents * sizeof(edg_wll_Event *));
                        }
                        if ((retval = edg_wll_ParseEvent(context, line, &h->events[nevents])) != 0) {
-                               char    *ed;
+                               char    *ed;
                                free(line);
                                err.code = retval;
                                edg_wll_Error(context,NULL,&ed);
@@ -152,7 +158,6 @@ static int lb_open(void *fpctx, void *bhandle, const char *uri, void **handle) {
                        err.desc = "reading LB logline";
                        err.source = "lb_plugin.c:read_line()";
                        glite_jp_stack_error(ctx,&err);
-
                        goto fail;
                }
        }
@@ -171,8 +176,8 @@ static int lb_open(void *fpctx, void *bhandle, const char *uri, void **handle) {
        fprintf(stderr,"lb_plugin: opened %d events\n", nevents);
 #endif
 
-       /* count state of job given by loaded events */
-       if ((retval = lb_status(h->events, &(h->status))) != 0) goto fail;
+       /* count state and status hiftory of the job given by the loaded events */
+       if ((retval = lb_status(h)) != 0) goto fail;
 
        *handle = (void *)h;
 
@@ -216,6 +221,15 @@ static int lb_close(void *fpctx,void *handle) {
        if (h->status.state != EDG_WLL_JOB_UNDEF) 
                edg_wll_FreeStatus(&h->status);
 
+       if (h->fullStatusHistory) {
+               i = 0;
+               while  (h->fullStatusHistory[i]) {
+                       if (h->fullStatusHistory[i]->reason) free(h->fullStatusHistory[i]->reason);
+                       free (h->fullStatusHistory[i]);
+                       i++;
+               }
+       }
+
        free(h);
 
 #ifdef PLUGIN_DEBUG
@@ -238,151 +252,149 @@ static int lb_query(void *fpctx,void *handle,const char *attr,glite_jp_attrval_t
         memset(&err,0,sizeof err);
         err.source = __FUNCTION__;
 
+       if ((h->events == NULL) || 
+           (h->status.state == EDG_WLL_JOB_UNDEF) ||
+           (h->fullStatusHistory == NULL) ) {
+                *attrval = NULL;
+                err.code = ENOENT;
+                trio_asprintf(&err.desc,"There is no job information to query.");
+                return glite_jp_stack_error(ctx,&err);
+       }
+
         if (strcmp(attr, GLITE_JP_LB_user) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = check_strdup(h->status.owner);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.owner) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       av[0].value = strdup(h->status.owner);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_jobId) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = edg_wlc_JobIdUnparse(h->status.jobId);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
-       } else if (strcmp(attr, GLITE_JP_LB_parent) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = edg_wlc_JobIdUnparse(h->status.parent_job);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.jobId) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       av[0].value = edg_wlc_JobIdUnparse(h->status.jobId);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_VO) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-                if (h->events) {
-                        i = 0;
-                        while (h->events[i]) {
-                                if (h->events[i]->type == EDG_WLL_EVENT_REGJOB) {
-                                       struct cclassad *ad;
-                                       char *string_vo = NULL; 
-
-                                       ad = cclassad_create(h->events[i]->regJob.jdl);
-                                       if (ad) {
-                                               if (!cclassad_evaluate_to_string(ad, "VirtualOrganisation", &string_vo))
-                                                       string_vo = NULL;
-                                               
+               i = 0;
+               while (h->events[i]) {
+                       if (h->events[i]->type == EDG_WLL_EVENT_REGJOB) {
+                               struct cclassad *ad;
+                               char *string_vo = NULL; 
+
+                               ad = cclassad_create(h->events[i]->regJob.jdl);
+                               if (ad) {
+                                       if (cclassad_evaluate_to_string(ad, "VirtualOrganisation", &string_vo)) {
+                                               av = calloc(2, sizeof(glite_jp_attrval_t));
+                                               av[0].name = strdup(attr);
                                                av[0].value = check_strdup(string_vo);
-                                               cclassad_delete(ad);
-                                               if (string_vo) free(string_vo);
+                                               av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
                                        }
-                                        av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
-                                        break;
-                                }
-                                i++;
-                        }
-                }
+                                       cclassad_delete(ad);
+                                       if (string_vo) free(string_vo);
+                               }
+                               break;
+                       }
+                       i++;
+               }
         } else if (strcmp(attr, GLITE_JP_LB_eNodes) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-                if (h->events) {
-                        i = 0;
-                        while (h->events[i]) {
-                                if (h->events[i]->type == EDG_WLL_EVENT_REGJOB) {
-                                       struct cclassad *ad;
-                                       char *string_nodes = NULL; 
-
-                                       ad = cclassad_create(h->events[i]->regJob.jdl);
-                                       if (ad) {
-                                               if (!cclassad_evaluate_to_string(ad, "max_nodes_running", &string_nodes))
-                                                       string_nodes = NULL;
-                                               
+               i = 0;
+               while (h->events[i]) {
+                       if (h->events[i]->type == EDG_WLL_EVENT_REGJOB) {
+                               struct cclassad *ad;
+                               char *string_nodes = NULL; 
+
+                               ad = cclassad_create(h->events[i]->regJob.jdl);
+                               if (ad) {
+                                       if (cclassad_evaluate_to_string(ad, "max_nodes_running", &string_nodes)) {
+                                               av = calloc(2, sizeof(glite_jp_attrval_t));
+                                               av[0].name = strdup(attr);
                                                av[0].value = check_strdup(string_nodes);
-                                               cclassad_delete(ad);
-                                               if (string_nodes) free(string_nodes);
+                                               av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
                                        }
-                                        av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
-                                        break;
-                                }
-                                i++;
-                        }
-                }
+                                       cclassad_delete(ad);
+                                       if (string_nodes) free(string_nodes);
+                               }
+                               break;
+                       }
+                       i++;
+               }
         } else if (strcmp(attr, GLITE_JP_LB_eProc) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-                if (h->events) {
-                        i = 0;
-                        while (h->events[i]) {
-                                if (h->events[i]->type == EDG_WLL_EVENT_REGJOB) {
-                                       struct cclassad *ad;
-                                       char *string_nodes = NULL; 
-
-                                       ad = cclassad_create(h->events[i]->regJob.jdl);
-                                       if (ad) {
-                                               if (!cclassad_evaluate_to_string(ad, "NodeNumber", &string_nodes))
-                                                       string_nodes = NULL;
-                                               
+               i = 0;
+               while (h->events[i]) {
+                       if (h->events[i]->type == EDG_WLL_EVENT_REGJOB) {
+                               struct cclassad *ad;
+                               char *string_nodes = NULL; 
+
+                               ad = cclassad_create(h->events[i]->regJob.jdl);
+                               if (ad) {
+                                       if (cclassad_evaluate_to_string(ad, "NodeNumber", &string_nodes)) {
+                                               av = calloc(2, sizeof(glite_jp_attrval_t));
+                                               av[0].name = strdup(attr);
                                                av[0].value = check_strdup(string_nodes);
-                                               cclassad_delete(ad);
-                                               if (string_nodes) free(string_nodes);
+                                               av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
                                        }
-                                        av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
-                                        break;
-                                }
-                                i++;
-                        }
-                }
+                                       cclassad_delete(ad);
+                                       if (string_nodes) free(string_nodes);
+                               }
+                               break;
+                       }
+                       i++;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_aTag) == 0 ||
                    strcmp(attr, GLITE_JP_LB_rQType) == 0 ||
                    strcmp(attr, GLITE_JP_LB_eDuration) == 0) {
-               /* have to be retrieved from JDL */
-/*
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = "Not implemented yet.";
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
-*/
+               /* have to be retrieved from JDL, but probably obsolete and not needed at all */
                *attrval = NULL;
                err.code = ENOSYS;
-//             err.desc = "Not implemented yet.";
                trio_asprintf(&err.desc,"Attribute '%s' not implemented yet.",attr);
                return glite_jp_stack_error(ctx,&err);
        } else if (strcmp(attr, GLITE_JP_LB_RB) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = check_strdup(h->status.network_server);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.network_server) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       av[0].value = strdup(h->status.network_server);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_CE) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = check_strdup(h->status.destination);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.destination) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       av[0].value = strdup(h->status.destination);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_host) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = check_strdup(h->status.ce_node);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.ce_node) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       av[0].value = strdup(h->status.ce_node);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_UIHost) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = check_strdup(h->status.location);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.location) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       av[0].value = strdup(h->status.location);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_CPUTime) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               trio_asprintf(&av[0].value,"%d",
-                       h->status.cpuTime);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.cpuTime) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       trio_asprintf(&av[0].value,"%d", h->status.cpuTime);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_NProc) == 0) {
                /* currently LB hasn't got the info */
                *attrval = NULL;
                err.code = ENOSYS;
-//             err.desc = "Not implemented yet.";
                trio_asprintf(&err.desc,"Attribute '%s' not implemented yet.",attr);
                return glite_jp_stack_error(ctx,&err);
        } else if (strcmp(attr, GLITE_JP_LB_finalStatus) == 0) {
@@ -400,11 +412,13 @@ static int lb_query(void *fpctx,void *handle,const char *attr,glite_jp_attrval_t
                av[0].size = -1;
                av[0].timestamp = h->status.lastUpdateTime.tv_sec;
        } else if (strcmp(attr, GLITE_JP_LB_finalStatusReason) == 0) {
-               av = calloc(2, sizeof(glite_jp_attrval_t));
-               av[0].name = strdup(attr);
-               av[0].value = check_strdup(h->status.reason);
-               av[0].size = -1;
-               av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               if (h->status.reason) {
+                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                       av[0].name = strdup(attr);
+                       av[0].value = strdup(h->status.reason);
+                       av[0].size = -1;
+                       av[0].timestamp = h->status.lastUpdateTime.tv_sec;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_LRMSDoneStatus) == 0) {
                av = calloc(2, sizeof(glite_jp_attrval_t));
                av[0].name = strdup(attr);
@@ -412,32 +426,30 @@ static int lb_query(void *fpctx,void *handle,const char *attr,glite_jp_attrval_t
                av[0].size = -1;
                av[0].timestamp = h->status.lastUpdateTime.tv_sec;
        } else if (strcmp(attr, GLITE_JP_LB_LRMSStatusReason) == 0) {
-                if (h->events) {
-                        i = 0;
-                        while (h->events[i]) {
-                                if (h->events[i]->type == EDG_WLL_EVENT_DONE) {
-                                        av = calloc(2, sizeof(glite_jp_attrval_t));
-                                        av[0].name = strdup(attr);
-                                       av[0].value = check_strdup(h->events[i]->done.reason);
-                                        av[0].timestamp =
-                                                h->events[i]->any.timestamp.tv_sec;
-                                        break;
-                                }
-                                i++;
-                        }
-                }
+               i = 0;
+               while (h->events[i]) {
+                       if (h->events[i]->type == EDG_WLL_EVENT_DONE) {
+                               if (h->events[i]->done.reason) {
+                                       av = calloc(2, sizeof(glite_jp_attrval_t));
+                                       av[0].name = strdup(attr);
+                                       av[0].value = strdup(h->events[i]->done.reason);
+                                       av[0].size = -1;
+                                       av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
+                               }
+                               break;
+                       }
+                       i++;
+               }
        } else if (strcmp(attr, GLITE_JP_LB_retryCount) == 0) {
                av = calloc(2, sizeof(glite_jp_attrval_t));
                av[0].name = strdup(attr);
-               trio_asprintf(&av[0].value,"%d",
-                       h->status.resubmitted);
+               trio_asprintf(&av[0].value,"%d", h->status.resubmitted);
                av[0].size = -1;
                av[0].timestamp = h->status.lastUpdateTime.tv_sec;
        } else if (strcmp(attr, GLITE_JP_LB_additionalReason) == 0) {
                /* what is it? */
                *attrval = NULL;
                err.code = ENOSYS;
-//             err.desc = "Not implemented yet.";
                trio_asprintf(&err.desc,"Attribute '%s' not implemented yet.",attr);
                return glite_jp_stack_error(ctx,&err);
        } else if (strcmp(attr, GLITE_JP_LB_jobType) == 0) {
@@ -456,18 +468,58 @@ static int lb_query(void *fpctx,void *handle,const char *attr,glite_jp_attrval_t
        } else if (strcmp(attr, GLITE_JP_LB_nsubjobs) == 0) {
                av = calloc(2, sizeof(glite_jp_attrval_t));
                av[0].name = strdup(attr);
-               trio_asprintf(&av[0].value,"%d",
-                       h->status.children_num);
+               trio_asprintf(&av[0].value,"%d", h->status.children_num);
                av[0].size = -1;
                av[0].timestamp = h->status.lastUpdateTime.tv_sec;
-       } else if (strcmp(attr, GLITE_JP_LB_lastStatusHistory) == 0 ||
-                  strcmp(attr, GLITE_JP_LB_fullStatusHistory) == 0) {
-               /* complex types */
-               *attrval = NULL;
-               err.code = ENOSYS;
-//             err.desc = "Not implemented yet.";
-               trio_asprintf(&err.desc,"Attribute '%s' not implemented yet.",attr);
-               return glite_jp_stack_error(ctx,&err);
+       } else if (strcmp(attr, GLITE_JP_LB_lastStatusHistory) == 0) {
+/*
+               av = calloc(1 + EDG_WLL_NUMBER_OF_STATCODES, sizeof(glite_jp_attrval_t));
+               av[0].name = strdup(attr);
+               av[0].value = check_strdup(h->status.reason);
+               av[0].timestamp = h->status.stateEnterTime.tv_sec;
+               av[0].size = -1;
+               for (i=1; i<EDG_WLL_NUMBER_OF_STATCODES; i++) {
+                       av[i].name = strdup(attr);
+                       if (i == h->status.state) av[i].value = check_strdup(h->status.reason);
+                       av[i].timestamp = h->status.stateEnterTimes[i+1];
+                       av[i].size = -1;
+               }
+*/
+                i = 0; while (h->lastStatusHistory[i]) i++;
+                av = calloc(i+2, sizeof(glite_jp_attrval_t));
+                av[0].name = strdup(attr);
+                av[0].value = check_strdup(h->status.reason);
+                av[0].timestamp = h->status.stateEnterTime.tv_sec;
+                av[0].size = -1;
+               if (h->fullStatusHistory[0]) {
+                       av[1].name = edg_wll_StatToString(h->fullStatusHistory[0]->state);
+                       av[1].value = check_strdup(h->fullStatusHistory[0]->reason);
+                       av[1].timestamp = h->fullStatusHistory[0]->timestamp.tv_sec;
+                       av[1].size = -1;        
+               }
+                i = 0;
+                while (h->lastStatusHistory[i]) {
+                        av[i+2].name = edg_wll_StatToString(h->lastStatusHistory[i]->state);
+                        av[i+2].value = check_strdup(h->lastStatusHistory[i]->reason);
+                        av[i+2].timestamp = h->lastStatusHistory[i]->timestamp.tv_sec;
+                        av[i+2].size = -1;
+                        i++;
+                }
+       } else if (strcmp(attr, GLITE_JP_LB_fullStatusHistory) == 0) {
+               i = 0; while (h->fullStatusHistory[i]) i++;
+               av = calloc(i+1, sizeof(glite_jp_attrval_t));
+               av[0].name = strdup(attr);
+               av[0].value = check_strdup(h->status.reason);
+               av[0].timestamp = h->status.stateEnterTime.tv_sec;
+               av[0].size = -1;
+               i = 0;
+               while (h->fullStatusHistory[i]) {
+                       av[i+1].name = edg_wll_StatToString(h->fullStatusHistory[i]->state);
+                       av[i+1].value = check_strdup(h->fullStatusHistory[i]->reason);
+                       av[i+1].timestamp = h->fullStatusHistory[i]->timestamp.tv_sec;
+                       av[i+1].size = -1;      
+                       i++;
+               }
        } else if (strncmp(attr, GLITE_JP_LBTAG_NS, sizeof(GLITE_JP_LBTAG_NS)-1) == 0) {
                tag = strrchr(attr, ':');
                if (h->events && tag) {
@@ -493,72 +545,97 @@ static int lb_query(void *fpctx,void *handle,const char *attr,glite_jp_attrval_t
                        }
                }
        } else if (strcmp(attr, GLITE_JP_LB_JDL) == 0) {
-               for (i=0; h->events[i]; i++) if (h->events[i]->type == EDG_WLL_EVENT_REGJOB 
-                       && h->events[i]->regJob.jdl)
-               {
-                       av = calloc(2, sizeof(glite_jp_attrval_t));
-                       av[0].name = strdup(attr);
-                       av[0].value = check_strdup(h->events[i]->regJob.jdl);
-                       av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
-                       av[0].size = -1;
-                       break;
+                i = 0;
+                while (h->events[i]) {
+                        if ((h->events[i]->type == EDG_WLL_EVENT_REGJOB) &&
+                           (h->events[i]->regJob.jdl) ) {
+                               av = calloc(2, sizeof(glite_jp_attrval_t));
+                               av[0].name = strdup(attr);
+                               av[0].value = strdup(h->events[i]->regJob.jdl);
+                               av[0].timestamp = h->events[i]->any.timestamp.tv_sec;
+                               av[0].size = -1;
+                               break;
+                       }
+                       i++;
                }
        } else {
                *attrval = NULL;
                err.code = EINVAL;
-//              err.desc = "No such attribute.";
                trio_asprintf(&err.desc,"No such attribute '%s'.",attr);
                return glite_jp_stack_error(ctx,&err);
        }
 
-       if (av[0].value) {
+       if (av && av[0].value) {
                for (i=0; av[i].name; i++) av[i].origin = GLITE_JP_ATTR_ORIG_FILE;
                *attrval = av;
                return 0;
-       }
-       else {
+       } else {
                *attrval = NULL;
                err.code = ENOENT;
-//             err.desc = "Value unknown";
-               trio_asprintf(&err.desc,"Value unknown for attribute '%s'.",av[0].name);
-               glite_jp_attrval_free(av,1);
+               trio_asprintf(&err.desc,"Value unknown for attribute '%s'.",attr);
+               if (av) glite_jp_attrval_free(av,1); // probably not needed
                return glite_jp_stack_error(ctx,&err);
        }
 }
 
 
-static int lb_status(edg_wll_Event **events, edg_wll_JobStat *status) {
+static int lb_status(void *handle) {
 
+       lb_handle       *h = (lb_handle *) handle;
         intJobStat     *js;
-        int            i, be_strict = 0;
+        int            maxnstates, nstates, i, be_strict = 0;
        char            *errstring;
+       edg_wll_JobStatCode old_state = EDG_WLL_JOB_UNDEF;
         
         js = calloc(1, sizeof(intJobStat));
        init_intJobStat(js);
 
-       /* TODO:
-       edg_wll_SortEvents(events);
-        */
+       edg_wll_SortPEvents(h->events);
 
+       maxnstates = INITIAL_NUMBER_STATES;
+       nstates = 0;
+       h->fullStatusHistory = calloc(maxnstates, sizeof(lb_historyStatus *));
        i = 0;
-        while (events[i])  
+        while (h->events[i])  
         {
-               /* XXX: job owner and jobId not filled from events normally */
-               if (events[i]->any.type == EDG_WLL_EVENT_REGJOB) {
-                       js->pub.owner = check_strdup(events[i]->any.user);
-                       if (edg_wlc_JobIdDup(events[i]->any.jobId,&js->pub.jobId)) {
+               /* realloc the fullStatusHistory if needed */
+               if (nstates >= maxnstates) {
+                       maxnstates <<= 1;
+                       h->fullStatusHistory = realloc(h->fullStatusHistory, maxnstates * sizeof(lb_historyStatus *));
+               }
+
+               /* job owner and jobId not filled from events normally */
+               if (h->events[i]->any.type == EDG_WLL_EVENT_REGJOB) {
+                       js->pub.owner = check_strdup(h->events[i]->any.user);
+                       if (edg_wlc_JobIdDup(h->events[i]->any.jobId,&js->pub.jobId)) {
                                goto err;
                        }
                }
-               if (processEvent(js, events[i], 0, be_strict, &errstring) == RET_FATAL) {
+               /* Process Event and update the state */
+               if (processEvent(js, h->events[i], 0, be_strict, &errstring) == RET_FATAL) {
                        goto err;
                }
+
+               /* if the state has changed, update the status history */
+               if (js->pub.state != old_state) {
+                       h->fullStatusHistory[nstates] = calloc(1,sizeof(lb_historyStatus));
+                       h->fullStatusHistory[nstates]->state = js->pub.state;
+                       h->fullStatusHistory[nstates]->timestamp.tv_sec = js->pub.stateEnterTime.tv_sec;
+                       h->fullStatusHistory[nstates]->timestamp.tv_usec = js->pub.stateEnterTime.tv_usec;
+                       h->fullStatusHistory[nstates]->reason = check_strdup(js->pub.reason);           
+                       if (js->pub.state == EDG_WLL_JOB_WAITING) {
+                               h->lastStatusHistory = &h->fullStatusHistory[nstates];
+                       }
+                       old_state = js->pub.state;
+                       nstates++;
+               }
+
                i++;
        }
 
-       memcpy(status, &js->pub, sizeof(edg_wll_JobStat));
+       memcpy(&h->status, &js->pub, sizeof(edg_wll_JobStat));
 
-       // XXX: awful, hopefully working
+       // not very clean, but working
        memset(&js->pub, 0, sizeof(edg_wll_JobStat));
        destroy_intJobStat(js);