~ubuntu-branches/ubuntu/precise/torque/precise-updates

« back to all changes in this revision

Viewing changes to src/server/req_jobobit.c

  • Committer: Bazaar Package Importer
  • Author(s): Dominique Belhachemi
  • Date: 2010-05-17 20:56:46 UTC
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100517205646-yjsoqs5r1s9xpnu9
Tags: upstream-2.4.8+dfsg
ImportĀ upstreamĀ versionĀ 2.4.8+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
#include <stdio.h>
89
89
#include <stdlib.h>
90
90
#include <string.h>
 
91
#include <time.h>
 
92
#include <unistd.h>
 
93
#include <errno.h>
91
94
#include "libpbs.h"
92
95
#include "server_limits.h"
93
96
#include "list_link.h"
94
97
#include "attribute.h"
95
98
#include "resource.h"
96
99
#include "server.h"
97
 
#include "job.h"
 
100
#include "pbs_job.h"
98
101
#include "credential.h"
99
102
#include "batch_request.h"
100
103
#include "work_task.h"
108
111
 
109
112
 
110
113
#define RESC_USED_BUF 2048
 
114
#define JOBMUSTREPORTDEFAULTKEEP 30
111
115
 
112
116
/* External Global Data Items */
113
117
 
135
139
/* External Functions called */
136
140
 
137
141
extern void set_resc_assigned A_((job *, enum batch_op));
 
142
extern void cleanup_restart_file(job *);
138
143
 
139
144
/* Local public functions  */
140
145
 
141
146
void req_jobobit A_((struct batch_request *));
142
147
 
143
 
/* Local private functions */
144
 
 
145
 
static struct batch_request *setup_cpyfiles A_((struct batch_request *, job *, char *, char *, int, int));
146
148
 
147
149
 
148
150
/*
149
151
 * setup_from - setup the "from" name for a standard job file:
150
 
 * output, error, or chkpt
 
152
 * output, error, or checkpoint
151
153
 */
152
154
 
153
155
static char *setup_from(
178
180
 * batch request, then append the file pairs
179
181
 */
180
182
 
181
 
static struct batch_request *setup_cpyfiles(
 
183
struct batch_request *setup_cpyfiles(
182
184
 
183
185
        struct batch_request *preq,
184
186
        job  *pjob,
229
231
      pjob->ji_wattr[(int)JOB_ATR_job_owner].at_val.at_str,
230
232
      pcf->rq_owner);
231
233
 
232
 
    get_jobowner(
233
 
      pjob->ji_wattr[(int)JOB_ATR_euser].at_val.at_str,
234
 
      pcf->rq_user);
 
234
    if (tflag == JOBCKPFILE)
 
235
      {
 
236
      get_jobowner(
 
237
        PBS_DEFAULT_ADMIN,
 
238
        pcf->rq_user);
 
239
      }
 
240
    else
 
241
      {
 
242
      get_jobowner(
 
243
        pjob->ji_wattr[(int)JOB_ATR_euser].at_val.at_str,
 
244
        pcf->rq_user);
 
245
      }
235
246
 
236
247
    if (((pjob->ji_wattr[(int)JOB_ATR_egroup].at_flags & ATR_VFLAG_DEFLT) == 0) &&
237
248
        (pjob->ji_wattr[(int)JOB_ATR_egroup].at_val.at_str != 0))
325
336
  }
326
337
 
327
338
 
328
 
 
 
339
static struct batch_request *return_stdfile(
 
340
        struct batch_request *preq,
 
341
        job                  *pjob,
 
342
        enum job_atr          ati)
 
343
 
 
344
  {
 
345
 
 
346
  if (pjob->ji_wattr[(int)JOB_ATR_interactive].at_flags &&
 
347
      pjob->ji_wattr[(int)JOB_ATR_interactive].at_val.at_long)
 
348
    {
 
349
    return NULL;
 
350
    }
 
351
 
 
352
  if ((pjob->ji_wattr[(int)JOB_ATR_checkpoint_name].at_flags & ATR_VFLAG_SET) == 0)
 
353
    {
 
354
    return NULL;
 
355
    }
 
356
 
 
357
 
 
358
  /* if this file is joined to another then it doesn't have to get copied back */
 
359
  if (is_joined(pjob, ati))
 
360
    {
 
361
    return preq;
 
362
    }
 
363
 
 
364
  if (preq == NULL)
 
365
    {
 
366
    preq = alloc_br(PBS_BATCH_ReturnFiles);
 
367
    }
 
368
 
 
369
  strcpy(preq->rq_ind.rq_returnfiles.rq_jobid, pjob->ji_qs.ji_jobid);
 
370
 
 
371
  if (ati == JOB_ATR_errpath)
 
372
    {
 
373
    preq->rq_ind.rq_returnfiles.rq_return_stderr = TRUE;
 
374
    }
 
375
  else if (ati == JOB_ATR_outpath)
 
376
    {
 
377
    preq->rq_ind.rq_returnfiles.rq_return_stdout = TRUE;
 
378
    }
 
379
 
 
380
  return preq;
 
381
  }
329
382
 
330
383
 
331
384
/*
390
443
 
391
444
  if (is_joined(pjob, ati))
392
445
    {
393
 
    /* SUCCESS */
394
 
 
395
446
    return(preq);
396
447
    }
397
448
 
400
451
   * the keep list, MOM has already placed the file in the user's HOME
401
452
   * directory.  It doesn't need to be copied.
402
453
   */
403
 
 
404
454
  jkpattr = &pjob->ji_wattr[(int)JOB_ATR_keep];
405
455
 
406
456
  if ((jkpattr->at_flags & ATR_VFLAG_SET) &&
668
718
 
669
719
 
670
720
 
671
 
 
672
721
/*
673
722
 * on_job_exit - continue post-execution processing of a job that terminated.
674
723
 *
703
752
 
704
753
  int    IsFaked = 0;
705
754
  int  KeepSeconds = 0;
 
755
  int  PurgeIt = FALSE;
 
756
  int MustReport = FALSE;
706
757
  pbs_queue *pque;
 
758
  char *id = "on_job_exit";
 
759
  char namebuf[MAXPATHLEN + 1];
 
760
  char *namebuf2;
 
761
  int spool_file_exists;
 
762
  int rc = 0;
707
763
 
708
764
  extern void remove_job_delete_nanny(struct job *);
709
765
 
736
792
 
737
793
  if (pj == NULL)
738
794
    {
739
 
    sprintf(log_buffer, "on_job_exit called with INVALID pjob: %p",
740
 
            pjob);
 
795
    sprintf(log_buffer, "%s called with INVALID pjob: %p",
 
796
      id,
 
797
      pjob);
741
798
    }
742
799
  else
743
800
    {
744
 
    sprintf(log_buffer, "on_job_exit valid pjob: %p (substate=%d)",
745
 
            pjob,
746
 
            pjob->ji_qs.ji_substate);
 
801
    sprintf(log_buffer, "%s valid pjob: %p (substate=%d)",
 
802
      id,
 
803
      pjob,
 
804
      pjob->ji_qs.ji_substate);
747
805
    }
748
806
 
749
807
  log_event(
757
815
         log_buffer));
758
816
#endif /* END VNODETESTING */
759
817
 
760
 
  if ((handle = mom_comm(pjob, on_job_exit)) < 0)
 
818
  /*
 
819
   * we don't need a handle if we are complete. On starting up we will NOT have
 
820
   * a connection to mom, but still want to try and process the completed job
 
821
   */
 
822
  
 
823
  if ((pjob->ji_qs.ji_substate != JOB_SUBSTATE_COMPLETE) &&
 
824
    ((handle = mom_comm(pjob,on_job_exit)) < 0))
761
825
    {
762
826
    /* FAILURE - cannot connect to mom */
763
827
 
792
856
        }
793
857
 
794
858
      svr_setjobstate(
795
 
 
796
859
        pjob,
797
860
        JOB_STATE_EXITING,
798
 
        JOB_SUBSTATE_STAGEOUT);
 
861
        JOB_SUBSTATE_RETURNSTD);
799
862
 
800
863
      ptask->wt_type = WORK_Immed;
801
864
 
802
865
      /* NO BREAK, fall into stage out processing */
803
866
 
 
867
    case JOB_SUBSTATE_RETURNSTD:
 
868
      /* this is a new substate to TORQUE 2.4.0.  The purpose is to provide a
 
869
       * stage of the job exiting process that allows us to transfer stderr and
 
870
       * stdout files from the mom's spool directory back to the server spool
 
871
       * directory.  This will only be done if the job has been checkpointed,
 
872
       * and keep_completed is a positive value. This is so that a completed
 
873
       * job can be restarted from a checkpoint file.
 
874
       */
 
875
 
 
876
      if (ptask->wt_type != WORK_Deferred_Reply)
 
877
        {
 
878
        /* this is the very first call, have mom return the files */
 
879
 
 
880
        /* if job has been checkpointed and KeepSeconds > 0, copy the stderr
 
881
         * and stdout files back so that we can restart a completed
 
882
         * checkpointed job return_stdfile will only setup this request if
 
883
         * the job has a checkpoint file and the file is not joined to another
 
884
         *  file */
 
885
 
 
886
 
 
887
        KeepSeconds = 0;
 
888
 
 
889
        if ((pque = pjob->ji_qhdr) && (pque->qu_attr != NULL))
 
890
          {
 
891
          KeepSeconds = attr_ifelse_long(
 
892
                          &pque->qu_attr[(int)QE_ATR_KeepCompleted],
 
893
                          &server.sv_attr[(int)SRV_ATR_KeepCompleted],
 
894
                          0);
 
895
          }
 
896
 
 
897
        if (KeepSeconds > 0)
 
898
          {
 
899
 
 
900
 
 
901
          strcpy(namebuf, path_spool);
 
902
          strcat(namebuf, pjob->ji_qs.ji_fileprefix);
 
903
          strcat(namebuf, JOB_STDOUT_SUFFIX);
 
904
 
 
905
          /* allocate space for the string name plus ".SAV" */
 
906
          namebuf2 = malloc((strlen(namebuf) + 5) * sizeof(char));
 
907
 
 
908
          if (pjob->ji_qs.ji_un.ji_exect.ji_momaddr != pbs_server_addr)
 
909
            {
 
910
            preq = return_stdfile(preq, pjob, JOB_ATR_outpath);
 
911
            }
 
912
          else if (access(namebuf, F_OK) == 0)
 
913
            {
 
914
            strcpy(namebuf2, namebuf);
 
915
            strcat(namebuf2, ".SAV");
 
916
            if (link(namebuf, namebuf2))
 
917
              {
 
918
              log_err(errno,id,strerror(errno));
 
919
              }
 
920
            }
 
921
 
 
922
 
 
923
          namebuf[strlen(namebuf) - strlen(JOB_STDOUT_SUFFIX)] = '\0';
 
924
 
 
925
          strcat(namebuf, JOB_STDERR_SUFFIX);
 
926
 
 
927
 
 
928
          if (pjob->ji_qs.ji_un.ji_exect.ji_momaddr != pbs_server_addr)
 
929
            {
 
930
            preq = return_stdfile(preq, pjob, JOB_ATR_errpath);
 
931
            }
 
932
          else if (access(namebuf, F_OK) == 0)
 
933
            {
 
934
            strcpy(namebuf2, namebuf);
 
935
            strcat(namebuf2, ".SAV");
 
936
            if (link(namebuf, namebuf2))
 
937
              {
 
938
              log_err(errno,id,strerror(errno));
 
939
              }
 
940
            }
 
941
 
 
942
          free(namebuf2);
 
943
 
 
944
          }
 
945
 
 
946
 
 
947
        if (preq != NULL)
 
948
          {
 
949
          preq->rq_extra = (void *)pjob;
 
950
 
 
951
          if (issue_Drequest(handle, preq, on_job_exit, 0) == 0)
 
952
            {
 
953
            /* success, we'll come back after mom replies */
 
954
            return;
 
955
            }
 
956
 
 
957
          /* set up as if mom returned error, if we fall through to
 
958
           * here then we want to hit the error processing below
 
959
           * because something bad happened */
 
960
 
 
961
          IsFaked = 1;
 
962
 
 
963
          preq->rq_reply.brp_code   = PBSE_MOMREJECT;
 
964
 
 
965
          preq->rq_reply.brp_choice = BATCH_REPLY_CHOICE_NULL;
 
966
 
 
967
          preq->rq_reply.brp_un.brp_txt.brp_txtlen = 0;
 
968
 
 
969
 
 
970
          }
 
971
        else
 
972
          {
 
973
          /* we don't need to return files to the server spool,
 
974
             move on to see if we need to delete files */
 
975
 
 
976
          svr_setjobstate(
 
977
            pjob,
 
978
            JOB_STATE_EXITING,
 
979
            JOB_SUBSTATE_STAGEOUT);
 
980
 
 
981
          if (LOGLEVEL >= 6)
 
982
            {
 
983
            log_event(
 
984
              PBSEVENT_JOB,
 
985
              PBS_EVENTCLASS_JOB,
 
986
              pjob->ji_qs.ji_jobid,
 
987
              "no spool files to return");
 
988
            }
 
989
 
 
990
          ptask = set_task(WORK_Immed, 0, on_job_exit, pjob);
 
991
 
 
992
          if (ptask != NULL)
 
993
            {
 
994
            append_link(&pjob->ji_svrtask, &ptask->wt_linkobj, ptask);
 
995
            }
 
996
 
 
997
          return;
 
998
          }
 
999
 
 
1000
        }
 
1001
 
 
1002
      /* here we have a reply (maybe faked) from MOM about the request */
 
1003
      if (preq->rq_reply.brp_code != 0)
 
1004
        {
 
1005
        if (LOGLEVEL >= 3)
 
1006
          {
 
1007
          snprintf(log_buffer, LOG_BUF_SIZE, "request to return spool files failed on node '%s' for job %s%s",
 
1008
                   pjob->ji_wattr[(int)JOB_ATR_exec_host].at_val.at_str,
 
1009
                   pjob->ji_qs.ji_jobid,
 
1010
                   (IsFaked == 1) ? "*" : "");
 
1011
 
 
1012
          log_event(
 
1013
            PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
 
1014
            PBS_EVENTCLASS_JOB,
 
1015
            pjob->ji_qs.ji_jobid,
 
1016
            log_buffer);
 
1017
          }
 
1018
        } /* end if (preq->rq_reply.brp_code != 0) */
 
1019
 
 
1020
 
 
1021
      /*
 
1022
       * files (generally) moved ok, move on to the next phase by
 
1023
       * "faking" the immediate work task and falling through to
 
1024
       * the next case.
 
1025
       */
 
1026
 
 
1027
      free_br(preq);
 
1028
 
 
1029
      preq = NULL;
 
1030
 
 
1031
      svr_setjobstate(pjob, JOB_STATE_EXITING, JOB_SUBSTATE_STAGEOUT);
 
1032
 
 
1033
      ptask->wt_type = WORK_Immed;
 
1034
 
 
1035
 
 
1036
      /* NO BREAK -- FALL INTO NEXT CASE */
 
1037
 
804
1038
    case JOB_SUBSTATE_STAGEOUT:
805
1039
 
806
1040
      if (LOGLEVEL >= 4)
843
1077
 
844
1078
          if (issue_Drequest(handle, preq, on_job_exit, 0) == 0)
845
1079
            {
846
 
            /* success--we will re-enter this function when MOM replies to
847
 
             * our request */
 
1080
 
 
1081
            /* request sucessfully sent, we'll come back to this function
 
1082
               when mom replies */
848
1083
 
849
1084
            return;
850
1085
            }
874
1109
          }
875
1110
        else
876
1111
          {
877
 
          /* no files to copy, any to delete? */
 
1112
          /* no files to copy, go to next step */
878
1113
 
879
1114
          svr_setjobstate(
880
1115
            pjob,
887
1122
              PBSEVENT_JOB,
888
1123
              PBS_EVENTCLASS_JOB,
889
1124
              pjob->ji_qs.ji_jobid,
890
 
              "no files to copy - deleting job");
 
1125
              "no files to copy");
891
1126
            }
892
1127
 
893
1128
          ptask = set_task(WORK_Immed, 0, on_job_exit, pjob);
964
1199
       * "faking" the immediate work task.
965
1200
       */
966
1201
 
 
1202
 
 
1203
      /* check to see if we have saved the spool files, that means
 
1204
         the mom and server are sharing this spool directory.
 
1205
      pbs_server should take ownership of these files and rename them
 
1206
      see  JOB_SUBSTATE_RETURNSTD above*/
 
1207
 
 
1208
      strcpy(namebuf, path_spool);
 
1209
 
 
1210
      strcat(namebuf, pjob->ji_qs.ji_fileprefix);
 
1211
 
 
1212
      strcat(namebuf, JOB_STDOUT_SUFFIX);
 
1213
 
 
1214
      /* allocate space for the string name plus ".SAV" */
 
1215
      namebuf2 = malloc((strlen(namebuf) + 5) * sizeof(char));
 
1216
 
 
1217
      strcpy(namebuf2, namebuf);
 
1218
 
 
1219
      strcat(namebuf2, ".SAV");
 
1220
 
 
1221
      spool_file_exists = access(namebuf2, F_OK);
 
1222
 
 
1223
      if (spool_file_exists == 0)
 
1224
        {
 
1225
        if (link(namebuf2, namebuf))
 
1226
          {
 
1227
          log_err(errno,id,strerror(errno));
 
1228
          }
 
1229
        unlink(namebuf2);
 
1230
        }
 
1231
 
 
1232
 
 
1233
 
 
1234
      namebuf[strlen(namebuf) - strlen(JOB_STDOUT_SUFFIX)] = '\0';
 
1235
 
 
1236
      strcat(namebuf, JOB_STDERR_SUFFIX);
 
1237
      strcpy(namebuf2, namebuf);
 
1238
      strcat(namebuf2, ".SAV");
 
1239
 
 
1240
      spool_file_exists = access(namebuf2, F_OK);
 
1241
 
 
1242
      if (spool_file_exists == 0)
 
1243
        {
 
1244
 
 
1245
        if (link(namebuf2, namebuf))
 
1246
          {
 
1247
          log_err(errno,id,strerror(errno));
 
1248
          }
 
1249
        unlink(namebuf2);
 
1250
        }
 
1251
 
 
1252
      free(namebuf2);
 
1253
 
 
1254
 
967
1255
      free_br(preq);
968
1256
 
969
1257
      preq = NULL;
974
1262
 
975
1263
      /* NO BREAK - FALL INTO THE NEXT CASE */
976
1264
 
 
1265
 
977
1266
    case JOB_SUBSTATE_STAGEDEL:
978
1267
 
979
1268
      if (LOGLEVEL >= 4)
1007
1296
 
1008
1297
          if (issue_Drequest(handle, preq, on_job_exit, 0) == 0)
1009
1298
            {
1010
 
            /* successful--we will re-enter this function when the MOM replies to this request */
 
1299
            /* request issued,  we'll come back when mom replies */
1011
1300
 
1012
1301
            return;
1013
1302
            }
1025
1314
 
1026
1315
          IsFaked = 1;
1027
1316
 
1028
 
          /* set up as if mom returned error */
 
1317
          /* set up as if mom returned error since the issue_Drequest
 
1318
             failed */
1029
1319
 
1030
1320
          preq->rq_reply.brp_code = PBSE_MOMREJECT;
1031
1321
          preq->rq_reply.brp_choice = BATCH_REPLY_CHOICE_NULL;
1118
1408
        {
1119
1409
        strcpy(preq->rq_ind.rq_delete.rq_objname, pjob->ji_qs.ji_jobid);
1120
1410
 
1121
 
        issue_Drequest(handle, preq, release_req, 0);
 
1411
        rc = issue_Drequest(handle, preq, release_req, 0);
 
1412
 
 
1413
        if (rc != 0)
 
1414
          {
 
1415
          snprintf(log_buffer, LOG_BUF_SIZE, "DeleteJob issue_Drequest failure, rc = %d",
 
1416
                    rc);
 
1417
 
 
1418
          log_event(
 
1419
            PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
 
1420
            PBS_EVENTCLASS_JOB,
 
1421
            pjob->ji_qs.ji_jobid,
 
1422
            log_buffer);
 
1423
          }
1122
1424
 
1123
1425
        /* release_req will free preq and close connection */
1124
1426
        }
1130
1432
      if ((pjob->ji_qs.ji_svrflags & JOB_SVFLG_HERE) == 0)
1131
1433
        issue_track(pjob);
1132
1434
 
 
1435
      /* see if restarted job failed */
 
1436
 
 
1437
      if (pjob->ji_wattr[(int)JOB_ATR_checkpoint_restart_status].at_flags & ATR_VFLAG_SET)
 
1438
        {
 
1439
        char *pfailtype = NULL;
 
1440
        char *pfailure = NULL;
 
1441
        long *hold_val = 0;
 
1442
        char errMsg[21];
 
1443
        
 
1444
        strncpy(errMsg,
 
1445
          pjob->ji_wattr[(int)JOB_ATR_checkpoint_restart_status].at_val.at_str, 20);
 
1446
        
 
1447
        pfailtype = strtok(errMsg," ");
 
1448
        if (pfailtype != NULL)
 
1449
          pfailure = strtok(NULL," ");
 
1450
        
 
1451
        if (pfailure != NULL)
 
1452
          {
 
1453
          if (memcmp(pfailure,"failure",7) == 0)
 
1454
            {
 
1455
            if (memcmp(pfailtype,"Temporary",9) == 0)
 
1456
              {
 
1457
              /* reque job */
 
1458
 
 
1459
              svr_setjobstate(pjob, JOB_STATE_QUEUED, JOB_SUBSTATE_QUEUED);
 
1460
              if (LOGLEVEL >= 4)
 
1461
                {
 
1462
                sprintf(log_buffer,
 
1463
                  "Requeueing job after checkpoint restart failure: %s",
 
1464
                  pjob->ji_wattr[(int)JOB_ATR_checkpoint_restart_status].at_val.at_str);
 
1465
 
 
1466
                log_event(
 
1467
                  PBSEVENT_JOB,
 
1468
                  PBS_EVENTCLASS_JOB,
 
1469
                  pjob->ji_qs.ji_jobid,
 
1470
                  log_buffer);
 
1471
                }
 
1472
              return;
 
1473
              }
 
1474
            /* 
 
1475
             * If we are deleting job after a failure then the first character
 
1476
             * of the comment should no longer be uppercase
 
1477
            */
 
1478
            else if (isupper(*pfailtype))
 
1479
              {
 
1480
              /* put job on hold */
 
1481
 
 
1482
              hold_val = &pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long;
 
1483
              *hold_val |= HOLD_s;
 
1484
              pjob->ji_wattr[(int)JOB_ATR_hold].at_flags |= ATR_VFLAG_SET;
 
1485
              pjob->ji_modified = 1;
 
1486
              svr_setjobstate(pjob, JOB_STATE_HELD, JOB_SUBSTATE_HELD);
 
1487
              if (LOGLEVEL >= 4)
 
1488
                {
 
1489
                sprintf(log_buffer,
 
1490
                  "Placing job on hold after checkpoint restart failure: %s",
 
1491
                  pjob->ji_wattr[(int)JOB_ATR_checkpoint_restart_status].at_val.at_str);
 
1492
 
 
1493
                log_event(
 
1494
                  PBSEVENT_JOB,
 
1495
                  PBS_EVENTCLASS_JOB,
 
1496
                  pjob->ji_qs.ji_jobid,
 
1497
                  log_buffer);
 
1498
                }
 
1499
              return;
 
1500
              }
 
1501
            }
 
1502
          }     
 
1503
        }
 
1504
 
1133
1505
      svr_setjobstate(pjob, JOB_STATE_COMPLETE, JOB_SUBSTATE_COMPLETE);
1134
1506
 
1135
1507
      if ((pque = pjob->ji_qhdr) && (pque != NULL))
1143
1515
 
1144
1516
    case JOB_SUBSTATE_COMPLETE:
1145
1517
 
1146
 
      if (LOGLEVEL >= 4)
 
1518
      if ((LOGLEVEL >= 4) && (ptask->wt_type == WORK_Immed))
1147
1519
        {
1148
1520
        log_event(
1149
1521
          PBSEVENT_JOB,
1160
1532
                        0);
1161
1533
        }
1162
1534
 
 
1535
      if (ptask->wt_type == WORK_Immed) 
 
1536
        {
 
1537
        /* first time in */
 
1538
 
 
1539
        if (((server.sv_attr[(int)SRV_ATR_JobMustReport].at_flags & ATR_VFLAG_SET) != 0)
 
1540
          && (server.sv_attr[(int)SRV_ATR_JobMustReport].at_val.at_long > 0))
 
1541
          {
 
1542
          MustReport = TRUE;
 
1543
          pjob->ji_wattr[(int)JOB_ATR_reported].at_val.at_long = 0;
 
1544
 
 
1545
          pjob->ji_wattr[(int)JOB_ATR_reported].at_flags =
 
1546
            ATR_VFLAG_SET | ATR_VFLAG_MODIFY;
 
1547
          job_save(pjob,SAVEJOB_FULL);
 
1548
          }
 
1549
        }
 
1550
      else if (((pjob->ji_wattr[(int)JOB_ATR_reported].at_flags & ATR_VFLAG_SET) != 0)
 
1551
        && (pjob->ji_wattr[(int)JOB_ATR_reported].at_val.at_long == 0))
 
1552
        {
 
1553
        MustReport = TRUE;
 
1554
        }
 
1555
 
1163
1556
      if (KeepSeconds <= 0)
1164
1557
        {
1165
 
        job_purge(pjob);
 
1558
        if (MustReport)
 
1559
          {
 
1560
          /*
 
1561
           * If job must report is set and keep_completed is 0,
 
1562
           * default to JOBMUSTREPORTDEFAULTKEEP seconds
 
1563
           */
 
1564
          KeepSeconds = JOBMUSTREPORTDEFAULTKEEP;
 
1565
          }
 
1566
        else
 
1567
          {
 
1568
          job_purge(pjob);
1166
1569
 
1167
 
        break;
 
1570
          break;
 
1571
          }
1168
1572
        }
1169
1573
 
1170
1574
      if (ptask->wt_type == WORK_Immed)
1171
1575
        {
1172
 
        /* first time in */
1173
 
 
1174
 
        ptask = set_task(WORK_Timed, time_now + KeepSeconds, on_job_exit, pjob);
 
1576
        /* is it first time in or server restart recovery */
 
1577
        
 
1578
        if ((handle == -1) &&
 
1579
            (pjob->ji_wattr[(int)JOB_ATR_comp_time].at_flags & ATR_VFLAG_SET))
 
1580
          {
 
1581
          /*
 
1582
           * server restart - if we already have a completion_time then we
 
1583
           * better be restarting.
 
1584
           * use the comp_time to determine task invocation time
 
1585
           */
 
1586
          ptask = set_task(WORK_Timed,
 
1587
            pjob->ji_wattr[(int)JOB_ATR_comp_time].at_val.at_long + KeepSeconds,
 
1588
            on_job_exit, pjob);
 
1589
          }
 
1590
        else
 
1591
          {
 
1592
          /* First time in - Set the job completion time */
 
1593
 
 
1594
          pjob->ji_wattr[(int)JOB_ATR_comp_time].at_val.at_long = (long)time(NULL);
 
1595
          pjob->ji_wattr[(int)JOB_ATR_comp_time].at_flags |= ATR_VFLAG_SET;
 
1596
 
 
1597
          ptask = set_task(WORK_Timed, time_now + KeepSeconds, on_job_exit, pjob);
 
1598
          job_save(pjob, SAVEJOB_FULL);
 
1599
          }
1175
1600
 
1176
1601
        if (ptask != NULL)
1177
1602
          {
1183
1608
      else
1184
1609
        {
1185
1610
        /* job has been around long enough */
1186
 
 
1187
 
        job_purge(pjob);
 
1611
        
 
1612
        /*
 
1613
         * If the jobs must report attribute is set
 
1614
         * then skip the job if it has not yet reported to the scheduler.
 
1615
         */
 
1616
        
 
1617
        PurgeIt = TRUE;
 
1618
        if (((pjob->ji_wattr[(int)JOB_ATR_reported].at_flags & ATR_VFLAG_SET) != 0)
 
1619
          && (pjob->ji_wattr[(int)JOB_ATR_reported].at_val.at_long == 0))
 
1620
          {
 
1621
          if (LOGLEVEL >= 7)
 
1622
            {
 
1623
            sprintf(log_buffer, "Bypassing job %s waiting for purge completed command",
 
1624
              pjob->ji_qs.ji_jobid);
 
1625
            log_record(
 
1626
              PBSEVENT_JOB,
 
1627
              PBS_EVENTCLASS_JOB,
 
1628
              pjob->ji_qs.ji_jobid,
 
1629
              log_buffer);
 
1630
            }
 
1631
 
 
1632
          ptask = set_task(WORK_Timed,time_now +
 
1633
                JOBMUSTREPORTDEFAULTKEEP,on_job_exit,pjob);
 
1634
 
 
1635
          if (ptask != NULL)
 
1636
            {
 
1637
            /* insure that work task will be removed if job goes away */
 
1638
 
 
1639
            append_link(&pjob->ji_svrtask,&ptask->wt_linkobj,ptask);
 
1640
            }
 
1641
            
 
1642
            PurgeIt = FALSE;
 
1643
          }
 
1644
        if (PurgeIt)
 
1645
          {
 
1646
          job_purge(pjob);
 
1647
          }
1188
1648
        }
1189
1649
 
1190
1650
      break;
1215
1675
  int        handle;
1216
1676
  int        newstate;
1217
1677
  int        newsubst;
 
1678
  int        rc = 0;
1218
1679
  job       *pjob;
1219
1680
 
1220
1681
  struct batch_request *preq;
1543
2004
 
1544
2005
        preq->rq_extra = (void *)pjob;
1545
2006
 
1546
 
        issue_Drequest(handle, preq, release_req, 0);
 
2007
        rc = issue_Drequest(handle, preq, release_req, 0);
 
2008
 
 
2009
        if (rc != 0)
 
2010
          {
 
2011
          snprintf(log_buffer, LOG_BUF_SIZE, "DeleteJob issue_Drequest failure, rc = %d",
 
2012
                    rc);
 
2013
 
 
2014
          log_event(
 
2015
            PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
 
2016
            PBS_EVENTCLASS_JOB,
 
2017
            pjob->ji_qs.ji_jobid,
 
2018
            log_buffer);
 
2019
          }
1547
2020
 
1548
2021
        /* release_req will free preq and close connection */
1549
2022
        }
1594
2067
  struct work_task *ptask)
1595
2068
 
1596
2069
  {
1597
 
  if (LOGLEVEL >= 7)
1598
 
    {
1599
 
    log_event(
1600
 
      PBSEVENT_ERROR | PBSEVENT_JOB,
1601
 
      PBS_EVENTCLASS_JOB,
1602
 
      "",
1603
 
      "wait_for_send - job obit racing retry");
1604
 
    }
1605
 
 
1606
2070
  req_jobobit((struct batch_request *)ptask->wt_parm1);
1607
2071
 
1608
2072
  return;
1637
2101
 
1638
2102
 
1639
2103
 
 
2104
/**
 
2105
 * Gets the latest stored used resource information (cput, mem, walltime, etc.)
 
2106
 * about the given job. 
 
2107
 *
 
2108
 */
 
2109
 
 
2110
int get_used(
 
2111
 
 
2112
  svrattrl   *patlist,   /* I */
 
2113
  char       *acctbuf)  /* O */
 
2114
 
 
2115
  {
 
2116
  int       retval = FALSE;
 
2117
  int       amt;
 
2118
  int       need;
 
2119
 
 
2120
  amt = RESC_USED_BUF - strlen(acctbuf);
 
2121
 
 
2122
  while (patlist != NULL)
 
2123
    {
 
2124
    if (strcmp(patlist->al_name, ATTR_session) == 0)
 
2125
      {
 
2126
      patlist = (svrattrl *)GET_NEXT(patlist->al_link);
 
2127
      continue;
 
2128
      }
 
2129
 
 
2130
    need = strlen(patlist->al_name) + strlen(patlist->al_value) + 3;
 
2131
 
 
2132
    if (patlist->al_resc)
 
2133
      {
 
2134
      need += strlen(patlist->al_resc) + 3;
 
2135
      }
 
2136
 
 
2137
    if (need < amt)
 
2138
      {
 
2139
      strcat(acctbuf, "\n");
 
2140
      strcat(acctbuf, patlist->al_name);
 
2141
 
 
2142
      if (patlist->al_resc)
 
2143
        {
 
2144
        strcat(acctbuf, ".");
 
2145
        strcat(acctbuf, patlist->al_resc);
 
2146
        }
 
2147
 
 
2148
      strcat(acctbuf, "=");
 
2149
 
 
2150
      strcat(acctbuf, patlist->al_value);
 
2151
 
 
2152
      amt -= need;
 
2153
      }
 
2154
 
 
2155
    retval = TRUE;
 
2156
 
 
2157
    patlist = (svrattrl *)GET_NEXT(patlist->al_link);
 
2158
    }
 
2159
 
 
2160
  return (retval);
 
2161
  }  /* END get_used() */
 
2162
 
 
2163
 
 
2164
/**
 
2165
 * Encodes the used resource information (cput, mem, walltime, etc.)
 
2166
 * about the given job.
 
2167
 *
 
2168
 */
 
2169
 
 
2170
#ifdef USESAVEDRESOURCES
 
2171
void encode_job_used(
 
2172
 
 
2173
  job        *pjob,   /* I */
 
2174
  tlist_head *phead)  /* O */
 
2175
 
 
2176
  {
 
2177
  attribute  *at;
 
2178
  attribute_def  *ad;
 
2179
  resource  *rs;
 
2180
 
 
2181
  at = &pjob->ji_wattr[JOB_ATR_resc_used];
 
2182
  ad = &job_attr_def[JOB_ATR_resc_used];
 
2183
 
 
2184
  if ((at->at_flags & ATR_VFLAG_SET) == 0)
 
2185
    {
 
2186
    return;
 
2187
    }
 
2188
 
 
2189
  for (rs = (resource *)GET_NEXT(at->at_val.at_list);
 
2190
       rs != NULL;
 
2191
       rs = (resource *)GET_NEXT(rs->rs_link))
 
2192
    {
 
2193
    resource_def *rd = rs->rs_defin;
 
2194
    attribute     val;
 
2195
    int           rc;
 
2196
 
 
2197
    val = rs->rs_value; /* copy resource attribute */
 
2198
 
 
2199
    rc = rd->rs_encode(
 
2200
 
 
2201
           &val,
 
2202
           phead,
 
2203
           ad->at_name,
 
2204
           rd->rs_name,
 
2205
           ATR_ENCODE_CLIENT);
 
2206
 
 
2207
    if (rc < 0)
 
2208
      break;
 
2209
    }  /* END for (rs) */
 
2210
 
 
2211
  return;
 
2212
  }  /* END encode_job_used() */
 
2213
#endif    /* USESAVEDRESOURCES */
 
2214
 
 
2215
 
1640
2216
 
1641
2217
 
1642
2218
 
1650
2226
  struct batch_request *preq)  /* I */
1651
2227
 
1652
2228
  {
 
2229
#ifdef USESAVEDRESOURCES
 
2230
  char   id[] = "req_jobobit";
 
2231
#endif    /* USESAVEDRESOURCES */
1653
2232
  int    alreadymailed = 0;
1654
 
  int    amt;
1655
2233
  int    bad;
1656
 
  char     acctbuf[RESC_USED_BUF];
 
2234
  char   acctbuf[RESC_USED_BUF];
1657
2235
  int    accttail;
1658
2236
  int    exitstatus;
1659
 
  char    mailbuf[RESC_USED_BUF];
1660
 
  int    need;
 
2237
  int    have_resc_used = FALSE;
 
2238
  char   mailbuf[RESC_USED_BUF];
1661
2239
  int    newstate;
1662
2240
  int    newsubst;
1663
2241
  char   *pc;
1664
 
  job   *pjob;
1665
 
  char        jobid[PBS_MAXSVRJOBID+1];
 
2242
  job    *pjob;
 
2243
  char   jobid[PBS_MAXSVRJOBID+1];
1666
2244
 
1667
2245
  struct work_task *ptask;
1668
2246
  svrattrl  *patlist;
1669
2247
  unsigned int    dummy;
1670
2248
 
1671
 
  if (LOGLEVEL >= 7)
1672
 
    {
1673
 
    log_event(
1674
 
      PBSEVENT_ERROR | PBSEVENT_JOB,
1675
 
      PBS_EVENTCLASS_JOB,
1676
 
      preq->rq_ind.rq_jobobit.rq_jid,
1677
 
      "obit received");
1678
 
    }
1679
 
 
1680
2249
  strcpy(jobid, preq->rq_ind.rq_jobobit.rq_jid);  /* This will be needed later for logging after preq is freed. */
1681
 
 
1682
2250
  pjob = find_job(preq->rq_ind.rq_jobobit.rq_jid);
1683
2251
 
1684
2252
  if ((pjob == NULL) ||
1708
2276
      }
1709
2277
 
1710
2278
    log_event(
1711
 
 
1712
2279
      PBSEVENT_ERROR | PBSEVENT_JOB,
1713
2280
      PBS_EVENTCLASS_JOB,
1714
2281
      jobid,
1723
2290
      {
1724
2291
      /* already in exit processing, ignore this request */
1725
2292
 
1726
 
      if (LOGLEVEL >= 7)
1727
 
        {
1728
 
        log_event(
1729
 
          PBSEVENT_ERROR | PBSEVENT_JOB,
1730
 
          PBS_EVENTCLASS_JOB,
1731
 
          preq->rq_ind.rq_jobobit.rq_jid,
1732
 
          "obit received - already in exit processing");
1733
 
        }
1734
 
 
1735
2293
      bad = PBSE_ALRDYEXIT;
1736
2294
      }
1737
2295
    else
1755
2313
      }
1756
2314
 
1757
2315
    req_reject(
1758
 
 
1759
2316
      bad,
1760
2317
      0,
1761
2318
      preq,
1774
2331
 
1775
2332
    if (ptask == NULL)
1776
2333
      {
1777
 
      if (LOGLEVEL >= 7)
1778
 
        {
1779
 
        log_event(
1780
 
          PBSEVENT_ERROR | PBSEVENT_JOB,
1781
 
          PBS_EVENTCLASS_JOB,
1782
 
          preq->rq_ind.rq_jobobit.rq_jid,
1783
 
          "obit received - race condition and ptask is NULL");
1784
 
        }
1785
 
 
1786
2334
      req_reject(PBSE_SYSTEM, 0, preq, NULL, NULL);
1787
2335
      }
1788
 
    else
1789
 
      {
1790
 
      if (LOGLEVEL >= 7)
1791
 
        {
1792
 
        log_event(
1793
 
          PBSEVENT_ERROR | PBSEVENT_JOB,
1794
 
          PBS_EVENTCLASS_JOB,
1795
 
          preq->rq_ind.rq_jobobit.rq_jid,
1796
 
          "obit received - race condition. Waiting for SIGCHLD, retry in 1 sec.");
1797
 
        }
1798
 
      }
1799
2336
 
1800
2337
    return;
1801
2338
    }
1830
2367
    }
1831
2368
 
1832
2369
  modify_job_attr(
1833
 
 
1834
2370
    pjob,
1835
2371
    patlist,
1836
2372
    ATR_DFLAG_MGWR | ATR_DFLAG_SvWR,
1851
2387
 
1852
2388
  accttail = strlen(acctbuf);
1853
2389
 
1854
 
  amt = RESC_USED_BUF - accttail;
1855
 
 
1856
 
  while (patlist != NULL)
 
2390
  have_resc_used = get_used(patlist, acctbuf);
 
2391
 
 
2392
#ifdef USESAVEDRESOURCES
 
2393
 
 
2394
  /* if we don't have resources from the obit, use what the job already had */
 
2395
 
 
2396
  if (!have_resc_used)
1857
2397
    {
1858
 
    need = strlen(patlist->al_name) + strlen(patlist->al_value) + 3;
1859
 
 
1860
 
    if (patlist->al_resc)
1861
 
      {
1862
 
      need += strlen(patlist->al_resc) + 3;
1863
 
      }
1864
 
 
1865
 
    if (need < amt)
1866
 
      {
1867
 
      strcat(acctbuf, "\n");
1868
 
      strcat(acctbuf, patlist->al_name);
1869
 
 
1870
 
      if (patlist->al_resc)
1871
 
        {
1872
 
        strcat(acctbuf, ".");
1873
 
        strcat(acctbuf, patlist->al_resc);
1874
 
        }
1875
 
 
1876
 
      strcat(acctbuf, "=");
1877
 
 
1878
 
      strcat(acctbuf, patlist->al_value);
1879
 
 
1880
 
      amt -= need;
1881
 
      }
1882
 
 
1883
 
    patlist = (svrattrl *)GET_NEXT(patlist->al_link);
 
2398
    struct batch_request *tmppreq;
 
2399
    if (LOGLEVEL >= 7)
 
2400
      {
 
2401
      log_event(
 
2402
        PBSEVENT_ERROR | PBSEVENT_JOB,
 
2403
        PBS_EVENTCLASS_JOB,
 
2404
        jobid,
 
2405
        "No resources used found");
 
2406
      }
 
2407
 
 
2408
    tmppreq = alloc_br(PBS_BATCH_JobObit);
 
2409
 
 
2410
    if (tmppreq == NULL)
 
2411
      {
 
2412
      /* FAILURE */
 
2413
 
 
2414
      sprintf(log_buffer, "cannot allocate memory for temp obit message");
 
2415
 
 
2416
      LOG_EVENT(
 
2417
        PBSEVENT_DEBUG,
 
2418
        PBS_EVENTCLASS_REQUEST,
 
2419
        id,
 
2420
        log_buffer);
 
2421
 
 
2422
      return;
 
2423
      }
 
2424
 
 
2425
    CLEAR_HEAD(tmppreq->rq_ind.rq_jobobit.rq_attr);
 
2426
 
 
2427
    encode_job_used(pjob, &tmppreq->rq_ind.rq_jobobit.rq_attr);
 
2428
 
 
2429
    patlist = (svrattrl *)GET_NEXT(tmppreq->rq_ind.rq_jobobit.rq_attr);
 
2430
 
 
2431
    have_resc_used = get_used(patlist, acctbuf);
 
2432
    
 
2433
    free_br(tmppreq);
1884
2434
    }
1885
2435
 
 
2436
#endif    /* USESAVEDRESOURCES */
 
2437
 
1886
2438
  strncat(mailbuf, (acctbuf + accttail), RESC_USED_BUF - strlen(mailbuf) - 1);
1887
2439
 
1888
2440
  mailbuf[RESC_USED_BUF - 1] = '\0';
1981
2533
        /* MOM could not restart job, setup for rerun */
1982
2534
 
1983
2535
        alreadymailed = setrerun(pjob);
1984
 
        pjob->ji_qs.ji_svrflags &= ~JOB_SVFLG_CHKPT;
 
2536
        pjob->ji_qs.ji_svrflags &= ~JOB_SVFLG_CHECKPOINT_FILE;
1985
2537
 
1986
2538
        break;
1987
2539
 
1996
2548
            PBSEVENT_JOB_USAGE | PBSEVENT_JOB_USAGE,
1997
2549
            PBS_EVENTCLASS_JOB,
1998
2550
            pjob->ji_qs.ji_jobid,
1999
 
            "received JOB_EXEC_INITRST, setting job CHKPT flag");
 
2551
            "received JOB_EXEC_INITRST, setting job CHECKPOINT_FLAG flag");
2000
2552
          }
2001
2553
 
2002
2554
        rel_resc(pjob);
2003
2555
 
2004
 
        pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HASRUN | JOB_SVFLG_CHKPT;
 
2556
        pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HASRUN | JOB_SVFLG_CHECKPOINT_FILE;
2005
2557
 
2006
2558
        svr_evaljobstate(pjob, &newstate, &newsubst, 1);
2007
2559
 
2022
2574
 
2023
2575
        alreadymailed = setrerun(pjob);
2024
2576
 
2025
 
        pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HASRUN | JOB_SVFLG_ChkptMig;
 
2577
        pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HASRUN | JOB_SVFLG_CHECKPOINT_MIGRATEABLE;
2026
2578
 
2027
2579
        break;
2028
2580
      }  /* END switch (exitstatus) */
2104
2656
        }
2105
2657
      }
2106
2658
 
 
2659
    /* remove checkpoint restart file if there is one */
 
2660
    
 
2661
    if (pjob->ji_wattr[(int)JOB_ATR_restart_name].at_flags & ATR_VFLAG_SET)
 
2662
      {
 
2663
      cleanup_restart_file(pjob);
 
2664
      }
 
2665
 
2107
2666
    /* "on_job_exit()" will be dispatched out of the main loop */
2108
2667
    }
2109
2668
  else
2110
2669
    {
 
2670
 
2111
2671
    /* Rerunning job, if not checkpointed, clear "resources_used and requeue job */
2112
2672
 
2113
 
    if ((pjob->ji_qs.ji_svrflags & (JOB_SVFLG_CHKPT | JOB_SVFLG_ChkptMig)) == 0)
 
2673
    if ((pjob->ji_qs.ji_svrflags & (JOB_SVFLG_CHECKPOINT_FILE | JOB_SVFLG_CHECKPOINT_MIGRATEABLE)) == 0)
2114
2674
      {
2115
2675
      job_attr_def[(int)JOB_ATR_resc_used].at_free(&pjob->ji_wattr[(int)JOB_ATR_resc_used]);
2116
2676
      }
2117
 
    else if (pjob->ji_qs.ji_svrflags & JOB_SVFLG_CHKPT)
 
2677
    else if (pjob->ji_qs.ji_svrflags & JOB_SVFLG_CHECKPOINT_FILE)
2118
2678
      {
2119
2679
      /* non-migratable checkpoint (cray), leave there */
2120
2680
      /* and just requeue the job         */
2133
2693
      }
2134
2694
 
2135
2695
    svr_setjobstate(
2136
 
 
2137
2696
      pjob,
2138
2697
      JOB_STATE_EXITING,
2139
2698
      pjob->ji_qs.ji_substate);
2154
2713
        }
2155
2714
      }
2156
2715
 
 
2716
#ifdef RERUNUSAGE
 
2717
 
 
2718
    /* replace new-lines with blanks for accounting record */
 
2719
 
 
2720
    for (pc = acctbuf;*pc;++pc)
 
2721
      {
 
2722
      if (*pc == '\n')
 
2723
        *pc = ' ';
 
2724
      }
 
2725
 
 
2726
    /* record accounting  */
 
2727
 
 
2728
    account_jobend(pjob, acctbuf);
 
2729
 
 
2730
#endif    /* RERUNUSAGE */
 
2731
 
 
2732
    /* remove checkpoint restart file if there is one */
 
2733
    
 
2734
    if (pjob->ji_wattr[(int)JOB_ATR_restart_name].at_flags & ATR_VFLAG_SET)
 
2735
      {
 
2736
      cleanup_restart_file(pjob);
 
2737
      }
 
2738
 
2157
2739
    /* "on_job_rerun()" will be dispatched out of the main loop */
2158
2740
    }  /* END else */
2159
2741