Files
maui/src/moab/MRM.c
T
dev 9a0042c61e Initial revision
git-svn-id: svn://opensvn.adaptivecomputing.com/maui/trunk@2 3f5042e3-fb1d-0410-be18-d6ca2573e517
2005-07-12 21:12:53 +00:00

5254 lines
101 KiB
C

/* HEADER */
#include "moab.h"
#include "msched-proto.h"
extern mlog_t mlog;
extern mrm_t MRM[];
extern mam_t MAM[];
extern const char *MRMState[];
extern const char *MRMType[];
extern const char *MRMAuthType[];
extern const char *MRMSubType[];
extern const char *MComp[];
extern const char *MDefReason[];
extern const char *MNodeState[];
extern const char *MRMFuncType[];
extern const char *MSockProtocol[];
extern const char *MWireProtocol[];
extern const char *MRMAttr[];
extern const char *MCSAlgoType[];
extern mattrlist_t MAList;
extern msys_t MSys;
extern mjob_t *MJob[];
extern mnode_t *MNode[];
extern msched_t MSched;
extern mframe_t MFrame[];
extern int MAQ[];
extern mstat_t MStat;
extern mqos_t MQOS[];
extern mclass_t MClass[];
extern mpar_t MPar[];
extern msim_t MSim;
extern mrmfunc_t MRMFunc[];
extern mx_t X;
#define MRMCfgParam "RMCFG"
int __MRMStartFunc(mrm_t *,int);
int __MRMEndFunc(mrm_t *,int);
#include "MLLI.c"
int MRMLoadModules()
{
const char *FName = "MRMLoadModules";
DBG(2,fRM) DPrint("%s()\n",
FName);
#if defined(__MLL22) || defined(__MLL31)
MLLLoadModule(&MRMFunc[mrmtLL]);
#endif /* __MLL22 || __MLL31 */
#ifdef __MPBS
MPBSLoadModule(&MRMFunc[mrmtPBS]);
#endif /* __MPBS */
#ifdef __MSGE
MSGELoadModule(&MRMFunc[mrmtSGE]);
#endif /* __MSGE */
MS3LoadModule(&MRMFunc[mrmtSSS]);
#ifdef __MRMS
MRMSLoadModule(&MRMFunc[mrmtRMS]);
#endif /* __MRMS */
#ifdef __MLSF
MLSFLoadModule(&MRMFunc[mrmtLSF]);
#endif /* __MLSF */
MWikiLoadModule(&MRMFunc[mrmtWiki]);
return(SUCCESS);
} /* END MRMLoadModules() */
int MRMInitialize()
{
int rmindex;
int Failure;
int rc;
int SC;
mrm_t *R;
const char *FName = "MRMInitialize";
DBG(2,fRM) DPrint("%s()\n",
FName);
Failure = FALSE;
for (rmindex = 0;MRM[rmindex].Type != mrmtNONE;rmindex++)
{
R = &MRM[rmindex];
if (R->Name[0] == '\0')
{
sprintf(R->Name,"%s.%d",
MRMType[R->Type],
R->Index);
}
if (MRMFunc[R->Type].RMInitialize == NULL)
{
DBG(7,fRM) DPrint("ALERT: cannot initialize RM (RM '%s' does not support function '%s')\n",
R->Name,
MRMFuncType[mrmRMInitialize]);
continue;
}
MUThread(
(int (*)(void))*MRMFunc[R->Type].RMInitialize,
R->P[0].Timeout,
&rc,
2,
NULL,
R,
&SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot initialize RM (RM '%s' failed in function '%s')\n",
R->Name,
MRMFuncType[mrmRMInitialize]);
MRMSetFailure(R,mrmRMInitialize,"cannot initialize interface");
Failure = TRUE;
continue;
}
R->RMNI = DEFAULT_MRMNETINTERFACE;
R->FailIteration = -1;
R->State = mrmsActive;
} /* END for (rmindex) */
if (Failure == TRUE)
{
return(FAILURE);
}
if (X.XRMInitialize != (int (*)())0)
(*X.XRMInitialize)(X.xd,NULL);
return(SUCCESS);
} /* END MRMInitialize() */
int MRMGetInfo()
{
mjob_t *J;
int JobCount;
int NodeCount;
static int APIFailureCount = 0;
const char *FName = "MRMGetInfo";
DBG(2,fRM) DPrint("%s()\n",
FName);
MStat.ActiveJobs = 0;
if (MSched.Mode == msmSim)
{
MSimRMGetInfo();
if (MSim.QueueChanged == TRUE)
{
MParUpdate(&MPar[0]);
}
}
else
{
/* meanwhile, back in the real world... */
/* clear runtime statistics */
MStat.EligibleJobs = 0;
MAQ[0] = -1;
MClusterClearUsage();
/* load resource data */
if (MSched.Iteration == 0)
{
MSched.InitialLoad = TRUE;
}
if ((X.XRMGetData != (int (*)())0) &&
((*X.XRMGetData)(X.xd,mcmBlock) == FAILURE))
{
char tmpLine[MAX_MLINE];
DBG(0,fRM) DPrint("WARNING: cannot load resource manager data at time %s\n",
MULToDString(&MSched.Time));
APIFailureCount++;
if (APIFailureCount > MSched.APIFailureThreshhold)
{
sprintf(tmpLine,"RMFAILURE: API has failed %d consecutive times on %s",
MSched.APIFailureThreshhold,
MULToDString(&MSched.Time));
MSysRegEvent(tmpLine,0,0,1);
APIFailureCount = 0;
}
return(FAILURE);
}
/* load RM node information */
if (MRMClusterQuery(&NodeCount,NULL) == SUCCESS)
{
DBG(1,fRM) DPrint("INFO: resources detected: %d\n",
NodeCount);
}
else
{
DBG(1,fRM) DPrint("WARNING: no resources detected\n");
}
/* load workload data */
if (MRMWorkloadQuery(&JobCount,NULL) == SUCCESS)
{
DBG(1,fALL) DPrint("INFO: jobs detected: %d\n",
JobCount);
}
else
{
DBG(1,fALL) DPrint("WARNING: no workload detected\n");
}
MSched.InitialLoad = FALSE;
MStatClearUsage(mxoNode,(1 << mlActive)|(1 << mlIdle),FALSE);
MClusterUpdateNodeState();
MParUpdate(&MPar[0]);
} /* END else if (MSched.Mode != msmSim) */
/* calculate statistics */
MStat.AvgQueuePH += MPar[0].L.IP->Usage[mptMaxPS][0] / 3600;
DBG(4,fRM)
{
DBG(4,fRM) DPrint("INFO: jobs in queue\n");
for (J = MJob[0]->Next;(J != NULL) && (J != MJob[0]);J = J->Next)
{
MJobShow(J,0,NULL);
}
}
APIFailureCount = 0;
return(SUCCESS);
} /* END MRMGetInfo() */
int MRMCheckEvents()
{
int rmindex;
int EventFound;
mrm_t *R;
const char *FName = "MRMCheckEvents";
DBG(9,fRM) DPrint("%s()\n",
FName);
if (MSched.Mode == msmSim)
{
return(FAILURE);
}
EventFound = FALSE;
for (rmindex = 0;MRM[rmindex].Type != mrmtNONE;rmindex++)
{
R = &MRM[rmindex];
if (MRMFunc[R->Type].RMEventQuery == NULL)
{
DBG(9,fRM) DPrint("ALERT: cannot query events on RM (RM '%s' does not support function '%s')\n",
R->Name,
MRMFuncType[mrmRMEventQuery]);
continue;
}
if ((*MRMFunc[R->Type].RMEventQuery)(R,NULL) == SUCCESS)
{
EventFound = TRUE;
break;
}
} /* END for (rmindex) */
if (EventFound == FALSE)
{
return(FAILURE);
}
return(SUCCESS);
} /* END MRMCheckEvents() */
int MRMClusterQuery(
int *RCount, /* O */
int *SC) /* O */
{
int rmindex;
int rc;
int tmpRCount = 0;
int TotalRCount;
mrm_t *R;
const char *FName = "MRMClusterQuery";
DBG(2,fRM) DPrint("%s()\n",
FName);
TotalRCount = 0;
for (rmindex = 0;MRM[rmindex].Type != mrmtNONE;rmindex++)
{
R = &MRM[rmindex];
if (MRMFunc[R->Type].ClusterQuery == NULL)
{
DBG(7,fRM) DPrint("ALERT: cannot load cluster resources on RM (RM '%s' does not support function '%s')\n",
R->Name,
MRMFuncType[mrmClusterQuery]);
continue;
}
__MRMStartFunc(R,mrmClusterQuery);
MUThread(
(int (*)(void))MRMFunc[R->Type].ClusterQuery,
R->P[0].Timeout,
&rc,
4,
NULL,
R,
&tmpRCount,
NULL, /* EMsg */
SC);
__MRMEndFunc(R,mrmClusterQuery);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot load cluster resources on RM (RM '%s' failed in function '%s')\n",
R->Name,
MRMFuncType[mrmClusterQuery]);
MRMSetFailure(R,mrmClusterQuery,"cannot get node info");
continue;
}
DBG(1,fRM) DPrint("INFO: %d %s resources detected on RM %s\n",
tmpRCount,
MRMType[R->Type],
R->Name);
TotalRCount += tmpRCount;
} /* END for (rmindex) */
if (RCount != NULL)
*RCount = TotalRCount;
if (TotalRCount == 0)
{
return(FAILURE);
}
return(SUCCESS);
} /* END MRMClusterQuery() */
int MRMWorkloadQuery(
int *WCount, /* O */
int *SC) /* O (optional) */
{
int rmindex;
int rc;
int tmpWCount;
int TotalWCount;
int nindex;
mnode_t *N;
mrm_t *R;
const char *FName = "MRMWorkloadQuery";
DBG(2,fRM) DPrint("%s()\n",
FName);
TotalWCount = 0;
/* reset dedicated resources */
for (nindex = 0;nindex < MAX_MNODE;nindex++)
{
N = MNode[nindex];
if ((N == NULL) || (N->Name[0] == '\0'))
break;
if (N->Name[0] == '\1')
continue;
memset(&N->DRes,0,sizeof(N->DRes));
}
for (rmindex = 0;MRM[rmindex].Type != mrmtNONE;rmindex++)
{
R = &MRM[rmindex];
if (MRMFunc[R->Type].WorkloadQuery == NULL)
{
DBG(7,fRM) DPrint("ALERT: cannot load cluster workload on RM (RM '%s' does not support function '%s')\n",
R->Name,
MRMFuncType[mrmWorkloadQuery]);
continue;
}
__MRMStartFunc(R,mrmWorkloadQuery);
MUThread(
(int (*)(void))MRMFunc[R->Type].WorkloadQuery,
R->P[0].Timeout,
&rc,
3,
NULL,
R,
&tmpWCount,
SC);
__MRMEndFunc(R,mrmWorkloadQuery);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot load cluster workload on RM (RM '%s' failed in function '%s')\n",
R->Name,
MRMFuncType[mrmWorkloadQuery]);
MRMSetFailure(R,mrmWorkloadQuery,"cannot get workload info");
continue;
}
DBG(1,fRM) DPrint("INFO: %d %s jobs detected on RM %s\n",
tmpWCount,
MRMType[R->Type],
R->Name);
TotalWCount += tmpWCount;
} /* END for (rmindex) */
if (WCount != NULL)
*WCount = TotalWCount;
if (TotalWCount == 0)
{
return(FAILURE);
}
return(SUCCESS);
} /* END MRMWorkloadQuery() */
int MRMJobStart(
mjob_t *J, /* I */
char *Msg, /* O: optional */
int *SC) /* O: optional */
{
int rqindex;
int rmindex;
int rmcount;
int rc;
mrm_t *R;
int RMList[MAX_MRM];
char tmpLine[MAX_MLINE];
char *MPtr;
const char *FName = "MRMJobStart";
DBG(1,fRM) DPrint("%s(%s,Msg,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL");
if (Msg != NULL)
MPtr = Msg;
else
MPtr = tmpLine;
MPtr[0] = '\0';
if (J == NULL)
{
return(FAILURE);
}
switch (MSched.Mode)
{
case msmSim:
return(MSimJobStart(J));
/*NOTREACHED*/
break;
case msmTest:
sprintf(MPtr,"cannot start job - test mode");
DBG(3,fRM) DPrint("INFO: cannot start job %s (%s)\n",
J->Name,
MPtr);
if (SC != NULL)
*SC = mscNoError;
return(FAILURE);
/*NOTREACHED*/
break;
default:
/* NO-OP */
break;
} /* END switch(MSched.Mode) */
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
}
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if ((R->FailIteration == MSched.Iteration) &&
(R->FailCount >= MAX_RMFAILCOUNT))
{
sprintf(MPtr,"cannot start job - fail iteration");
DBG(3,fRM) DPrint("INFO: cannot start job %s (%s)\n",
J->Name,
MPtr);
if (SC != NULL)
*SC = mscNoError;
return(FAILURE);
}
if (MRMFunc[R->Type].JobStart == NULL)
{
sprintf(MPtr,"cannot start job - RM '%s' does not support function '%s'",
R->Name,
MRMFuncType[mrmJobStart]);
DBG(3,fRM) DPrint("ALERT: cannot start job %s (%s)\n",
J->Name,
MPtr);
if (SC != NULL)
*SC = mscSysFailure;
return(FAILURE);
}
__MRMStartFunc(R,mrmJobStart);
MUThread(
(int (*)(void))MRMFunc[R->Type].JobStart,
R->P[0].Timeout,
&rc,
4,
NULL,
J,
R,
MPtr,
SC);
__MRMEndFunc(R,mrmJobStart);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot start job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobStart]);
MRMSetFailure(R,mrmJobStart,"cannot start job");
return(FAILURE);
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMJobStart() */
int MRMJobCancel(
mjob_t *J, /* I: req */
char *Message, /* I: opt */
int *SC) /* IO: opt */
{
int rqindex;
int rmindex;
int rmcount;
int rc;
mrm_t *R;
int RMList[MAX_MRM];
const char *FName = "MRMJobCancel";
DBG(1,fRM) DPrint("%s(%s,%s,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL",
(Message != NULL) ? Message : "NULL");
if (J == NULL)
{
return(FAILURE);
}
switch (MSched.Mode)
{
case msmSim:
return(MSimJobCancel(J));
/*NOTREACHED*/
break;
case msmTest:
DBG(3,fRM) DPrint("INFO: cannot cancel job '%s' (test mode)\n",
J->Name);
return(FAILURE);
/*NOTREACHED*/
break;
default:
/* NO-OP */
break;
} /* END switch(MSched.Mode) */
if (J->IFlags & (1 << mjifIsExiting))
{
return(SUCCESS);
}
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
}
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if (MSched.Iteration == R->FailIteration)
{
DBG(3,fRM) DPrint("INFO: cannot cancel job '%s' (fail iteration)\n",
J->Name);
return(FAILURE);
}
if (MRMFunc[R->Type].JobCancel == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot cancel job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobCancel]);
return(FAILURE);
}
__MRMStartFunc(R,mrmJobCancel);
MUThread(
(int (*)(void))MRMFunc[R->Type].JobCancel,
R->P[0].Timeout,
&rc,
5,
NULL,
J,
R,
Message,
NULL,
SC);
__MRMEndFunc(R,mrmJobCancel);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot cancel job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobCancel]);
MRMSetFailure(R,mrmJobStart,"cannot cancel job");
return(FAILURE);
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMJobCancel() */
int MRMJobGetProximateMNL(
mjob_t *J, /* I: req */
mrm_t *R,
mnodelist_t SMNL,
mnodelist_t DMNL,
long StartTime,
int DoExactMatch,
char *Message, /* I: opt */
int *SC) /* IO: opt */
{
int rc;
const char *FName = "MRMJobGetProximateMNL";
DBG(1,fRM) DPrint("%s(R,%s,SMNL,DMNL,%ld,%d,%s,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL",
StartTime,
DoExactMatch,
(Message != NULL) ? Message : "NULL");
if ((J == NULL) || (R == NULL))
{
return(FAILURE);
}
switch (MSched.Mode)
{
case msmSim:
return(FAILURE);
/*NOTREACHED*/
break;
default:
/* NO-OP */
break;
} /* END switch(MSched.Mode) */
/* single RM allowed */
if (MRMFunc[R->Type].JobGetProximateTasks == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot get proximate tasks for job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobGetProximateTasks]);
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobGetProximateTasks,
R->P[0].Timeout,
&rc,
8,
NULL,
J,
R,
SMNL,
DMNL,
StartTime,
DoExactMatch,
Message,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot get proximate tasks for job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobGetProximateTasks]);
return(FAILURE);
}
return(SUCCESS);
} /* END MRMJobGetProximateTasks() */
int MRMJobModify(
mjob_t *J, /* I: req */
char *Attr, /* I */
char *SubAttr, /* I */
char *Value, /* I */
int *SC) /* O: opt */
{
int rqindex;
int rmindex;
int rmcount;
int rc;
mrm_t *R;
int RMList[MAX_MRM];
const char *FName = "MRMJobModify";
DBG(1,fRM) DPrint("%s(%s,%s,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL",
(Attr != NULL) ? Attr : "NULL");
if (J == NULL)
{
return(FAILURE);
}
switch (MSched.Mode)
{
case msmSim:
return(MSimJobModify(J,Attr,SubAttr,Value,SC));
/*NOTREACHED*/
break;
case msmTest:
DBG(3,fRM) DPrint("INFO: cannot modify job '%s' (test mode)\n",
J->Name);
return(FAILURE);
/*NOTREACHED*/
break;
default:
/* NO-OP */
break;
} /* END switch(MSched.Mode) */
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
}
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if (MSched.Iteration == R->FailIteration)
{
DBG(3,fRM) DPrint("INFO: cannot modify job '%s' (fail iteration)\n",
J->Name);
return(FAILURE);
}
if (MRMFunc[R->Type].JobModify == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot modify job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobModify]);
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobModify,
R->P[0].Timeout,
&rc,
7,
NULL,
J,
R,
Attr,
SubAttr,
Value,
NULL,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot modify job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobModify]);
return(FAILURE);
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMJobModify() */
int MRMJobMigrate(
mjob_t *J, /* I */
mnalloc_t *NL, /* I */
int *SC) /* O: (optional) */
{
int rqindex;
int rmindex;
int rmcount;
int rc;
mrm_t *R;
int RMList[MAX_MRM];
const char *FName = "MRMJobMigrate";
DBG(1,fRM) DPrint("%s(%s,%s,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL",
(NL != NULL) ? "NL" : "NULL");
if (J == NULL)
{
return(FAILURE);
}
if (MJOBISACTIVE(J) == FALSE)
{
return(FAILURE);
}
switch (MSched.Mode)
{
case msmSim:
return(FAILURE);
/*NOTREACHED*/
break;
case msmTest:
DBG(3,fRM) DPrint("INFO: cannot migrate job '%s' (test mode)\n",
J->Name);
return(FAILURE);
/*NOTREACHED*/
break;
default:
/* NO-OP */
break;
} /* END switch(MSched.Mode) */
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
} /* END for (rmindex) */
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if (MRMFunc[R->Type].JobMigrate == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot migrate job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobMigrate]);
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobMigrate,
R->P[0].Timeout,
&rc,
5,
NULL,
J,
R,
NL,
NULL,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot migrate job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobMigrate]);
return(FAILURE);
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMJobMigrate() */
int MRMJobRequeue(
mjob_t *J, /* I: req */
mjob_t **JPeer, /* I: opt */
int *SC) /* IO: opt */
{
int rqindex;
int rmindex;
int rmcount;
int rc;
mrm_t *R;
int RMList[MAX_MRM];
const char *FName = "MRMJobRequeue";
DBG(1,fRM) DPrint("%s(%s,%s,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL",
(JPeer != NULL) ? "JPeer" : "NULL");
if (J == NULL)
{
return(FAILURE);
}
switch (MSched.Mode)
{
case msmSim:
return(MSimJobRequeue(J));
/*NOTREACHED*/
break;
case msmTest:
DBG(3,fRM) DPrint("INFO: cannot requeue job '%s' (test mode)\n",
J->Name);
return(FAILURE);
/*NOTREACHED*/
break;
default:
break;
} /* END switch(MSched.Mode) */
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
}
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if (MRMFunc[R->Type].JobRequeue == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot requeue job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobRequeue]);
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobRequeue,
R->P[0].Timeout,
&rc,
5,
NULL,
J,
R,
JPeer,
NULL,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot requeue job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobRequeue]);
return(FAILURE);
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMJobRequeue() */
int MRMJobSubmit(
char *JobDesc, /* I */
mrm_t *R, /* I */
mjob_t **J, /* O */
char *JobName, /* O */
char *Msg, /* O */
int *SC) /* O */
{
int rc;
if (MSched.Mode == msmSim)
{
/* return(MSimJobSubmit(MSched.Time,JobDesc,NULL,0)); */
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobSubmit,
R->P[0].Timeout,
&rc,
6,
NULL,
JobDesc,
R,
J,
JobName,
Msg,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot submit job (RM '%s' failed in function '%s')\n",
R->Name,
MRMFuncType[mrmJobSubmit]);
return(FAILURE);
}
return(SUCCESS);
} /* END MRMJobSubmit() */
int MRMJobSuspend(
mjob_t *J, /* I: req */
char *Msg, /* O (optional) */
int *SC) /* IO: (optional) */
{
int rqindex;
int rmindex;
int rmcount;
int rc;
mrm_t *R;
int RMList[MAX_MRM];
const char *FName = "MRMJobSuspend";
DBG(1,fRM) DPrint("%s(%s,Msg,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL");
if (J == NULL)
{
return(FAILURE);
}
if (MSched.Mode == msmSim)
{
return(MSimJobSuspend(J));
}
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
}
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if (MRMFunc[R->Type].JobSuspend == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot suspend job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobSuspend]);
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobSuspend,
R->P[0].Timeout,
&rc,
4,
NULL,
J,
R,
Msg,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot suspend job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobSuspend]);
return(FAILURE);
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMJobSuspend() */
int MRMJobCheckpoint(
mjob_t *J, /* I: req */
int TerminateJob, /* I: req */
char *Msg, /* O: opt */
int *SC) /* O: opt */
{
int rqindex;
int rmindex;
int rmcount;
int rc;
mrm_t *R;
int RMList[MAX_MRM];
const char *FName = "MRMJobCheckpoint";
DBG(1,fRM) DPrint("%s(%s,%d,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL",
TerminateJob);
if (J == NULL)
{
return(FAILURE);
}
if (MSched.Mode == msmSim)
{
return(MSimJobCheckpoint(J));
}
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
}
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if (MRMFunc[R->Type].JobCheckpoint == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot checkpoint job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobCheckpoint]);
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobCheckpoint,
R->P[0].Timeout,
&rc,
5,
NULL,
J,
R,
TerminateJob,
Msg,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot checkpoint job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobCheckpoint]);
return(FAILURE);
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMJobCheckpoint() */
int MRMJobResume(
mjob_t *J, /* I: req */
char *Msg, /* O: (optional) */
int *SC) /* IO: (optional) */
{
int rqindex;
int rmindex;
int rmcount;
int nindex;
int rc;
mrm_t *R;
mreq_t *RQ;
mnode_t *N;
int RMList[MAX_MRM];
const char *FName = "MRMJobResume";
DBG(1,fRM) DPrint("%s(%s,SC)\n",
FName,
(J != NULL) ? J->Name : "NULL");
if (J == NULL)
{
return(FAILURE);
}
if (MSched.Mode == msmSim)
{
return(MSimJobResume(J));
}
memset(RMList,0,sizeof(RMList));
rmcount = 0;
/* determine resource managers used */
for (rqindex = 0;rqindex < MAX_MREQ_PER_JOB;rqindex++)
{
if (J->Req[rqindex] == NULL)
continue;
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
if (RMList[rmindex] == J->Req[rqindex]->RMIndex)
{
break;
}
}
if (rmindex == rmcount)
{
RMList[rmindex] = J->Req[rqindex]->RMIndex;
rmcount++;
}
} /* END for (rqindex) */
for (rmindex = 0;rmindex < rmcount;rmindex++)
{
R = &MRM[RMList[rmindex]];
if (MRMFunc[R->Type].JobResume == NULL)
{
DBG(3,fRM) DPrint("ALERT: cannot resume job %s (RM '%s' does not support function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobResume]);
return(FAILURE);
}
MUThread(
(int (*)(void))MRMFunc[R->Type].JobResume,
R->P[0].Timeout,
&rc,
4,
NULL,
J,
R,
Msg,
SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot resume job %s (RM '%s' failed in function '%s')\n",
J->Name,
R->Name,
MRMFuncType[mrmJobResume]);
return(FAILURE);
}
} /* END for (rmindex) */
if (MResJCreate(J,NULL,MSched.Time,mjrActiveJob,NULL) == FAILURE)
{
DBG(0,fSCHED) DPrint("ERROR: cannot create reservation for job '%s'\n",
J->Name);
}
/* adjust per-node resource consumption */
RQ = J->Req[0];
for (nindex = 0;J->NodeList[nindex].N != NULL;nindex++)
{
N = J->NodeList[nindex].N;
/* adjust resource usage */
if (RQ->SDRes != NULL)
MCResRemove(&N->ARes,&N->CRes,RQ->SDRes,J->NodeList[nindex].TC,TRUE);
else
MCResRemove(&N->ARes,&N->CRes,&RQ->DRes,J->NodeList[nindex].TC,TRUE);
if (RQ->SDRes != NULL)
MCResAdd(&N->DRes,&N->CRes,RQ->SDRes,J->NodeList[nindex].TC,TRUE);
else
MCResAdd(&N->DRes,&N->CRes,&RQ->DRes,J->NodeList[nindex].TC,TRUE);
} /* END for (nindex) */
DBG(2,fSIM) DPrint("INFO: job %s successfully resumed on %d procs\n",
J->Name,
J->Request.TC);
return(SUCCESS);
} /* END MRMJobResume() */
int MRMLoadConfig(
char *RMName) /* I */
{
char IndexName[MAX_MNAME];
char Value[MAX_MLINE];
char *ptr;
mrm_t *R;
/* FORMAT: <KEY>=<VAL>[<WS><KEY>=<VAL>]... */
/* <VAL> -> <ATTR>=<VAL>[:<ATTR>=<VAL>]... */
/* load all/specified RM config info */
if (MSched.ConfigBuffer == NULL)
{
return(FAILURE);
}
if ((RMName == NULL) || (RMName[0] == '\0'))
{
/* load ALL RM config info */
ptr = MSched.ConfigBuffer;
IndexName[0] = '\0';
while (MCfgGetSVal(
MSched.ConfigBuffer,
&ptr,
MRMCfgParam,
IndexName,
NULL,
Value,
sizeof(Value),
0,
NULL) != FAILURE)
{
if (MRMFind(IndexName,&R) == FAILURE)
{
if (MRMAdd(IndexName,&R) == FAILURE)
{
/* unable to locate/create RM */
IndexName[0] = '\0';
continue;
}
MRMSetDefaults(R);
MOLoadPvtConfig((void **)R,mxoRM,NULL,NULL,NULL);
}
/* load RM specific attributes */
MRMProcessConfig(R,Value);
IndexName[0] = '\0';
} /* END while (MCfgGetSVal() != FAILURE) */
} /* END if ((RMName == NULL) || (RMName[0] == '\0')) */
else
{
/* load specified RM config info */
ptr = MSched.ConfigBuffer;
R = NULL;
while (MCfgGetSVal(
MSched.ConfigBuffer,
&ptr,
MRMCfgParam,
RMName,
NULL,
Value,
sizeof(Value),
0,
NULL) == SUCCESS)
{
if ((R == NULL) &&
(MRMFind(RMName,&R) == FAILURE))
{
if (MRMAdd(RMName,&R) == FAILURE)
{
/* unable to add standing reservation */
return(FAILURE);
}
MRMSetDefaults(R);
MOLoadPvtConfig((void **)R,mxoRM,NULL,NULL,NULL);
}
/* load RM attributes */
MRMProcessConfig(R,Value);
} /* END while (MCfgGetSVal() == SUCCESS) */
if (R == NULL)
{
return(FAILURE);
}
if (MRMCheckConfig(R) == FAILURE)
{
MRMDestroy(&R);
/* invalid standing reservation destroyed */
return(FAILURE);
}
} /* END else ((RMName == NULL) || (RMName[0] == '\0')) */
return(SUCCESS);
} /* END MRMLoadConfig() */
int MRMAdd(
char *RMName, /* I */
mrm_t **RP) /* O */
{
int rmindex;
mrm_t *R;
const char *FName = "MRMAdd";
DBG(6,fSTRUCT) DPrint("%s(%s,%s)\n",
FName,
(RMName != NULL) ? "RMName" : "NULL",
(RP != NULL) ? "RP" : "NULL");
if ((RMName == NULL) || (RMName[0] == '\0'))
{
return(FAILURE);
}
if (RP != NULL)
*RP = NULL;
for (rmindex = 0;rmindex < MAX_MRM;rmindex++)
{
R = &MRM[rmindex];
if ((R != NULL) && !strcmp(R->Name,RMName))
{
/* RM already exists */
if (RP != NULL)
*RP = R;
return(SUCCESS);
}
if ((R != NULL) &&
(R->Name[0] != '\0') &&
(R->Name[0] != '\1'))
{
continue;
}
/* empty slot found */
/* create/initialize new record */
if (R == NULL)
{
if (MRMCreate(RMName,&MRM[rmindex]) == FAILURE)
{
DBG(1,fALL) DPrint("ERROR: cannot alloc memory for RM '%s'\n",
RMName);
return(FAILURE);
}
R = &MRM[rmindex];
}
else if (R->Name[0] == '\0')
{
MUStrCpy(R->Name,RMName,sizeof(R->Name));
}
if (RP != NULL)
*RP = R;
R->Index = rmindex;
/* update RM record */
if (MSched.Mode != msmSim)
MCPRestore(mcpRM,RMName,(void *)R);
DBG(5,fSTRUCT) DPrint("INFO: RM %s added\n",
RMName);
return(SUCCESS);
} /* END for (rmindex) */
/* end of table reached */
DBG(1,fSTRUCT) DPrint("ALERT: RM table overflow. cannot add %s\n",
RMName);
return(SUCCESS);
} /* END MRMAdd() */
int MRMCreate(
char *RMName,
mrm_t *R)
{
if (R == NULL)
{
return(FAILURE);
}
/* use static memory for now */
memset(R,0,sizeof(mrm_t));
if ((RMName != NULL) && (RMName[0] != '\0'))
MUStrCpy(R->Name,RMName,sizeof(R->Name));
return(SUCCESS);
} /* END MRMCreate() */
int MRMFind(
char *RMName, /* I */
mrm_t **RP) /* O (optional) */
{
/* if found, return success with RP pointing to standing reservation. */
int rmindex;
mrm_t *R;
if (RP != NULL)
*RP = NULL;
if ((RMName == NULL) ||
(RMName[0] == '\0'))
{
return(FAILURE);
}
for (rmindex = 0;rmindex < MAX_MRM;rmindex++)
{
R = &MRM[rmindex];
if ((R == NULL) || (R->Name[0] == '\0') || (R->Name[0] == '\1'))
{
break;
}
if (strcmp(R->Name,RMName) != 0)
continue;
/* RM found */
if (RP != NULL)
*RP = R;
return(SUCCESS);
} /* END for (rmindex) */
/* entire table searched */
return(FAILURE);
} /* END MRMFind() */
int MRMSetDefaults(
mrm_t *R) /* I */
{
if (R == NULL)
{
return(FAILURE);
}
if (R->Type == 0)
{
/* set general defaults */
R->Type = DEFAULT_MRMTYPE;
R->AuthType = DEFAULT_MRMAUTHTYPE;
R->P[0].Timeout = DEFAULT_MRMTIMEOUT;
R->P[1].Timeout = DEFAULT_MRMTIMEOUT;
R->FailIteration = -1;
R->JobCounter = 0;
return(SUCCESS);
}
/* set rm type specific defaults */
switch(R->Type)
{
default:
/* NO-OP */
break;
} /* END switch(R->Type) */
return(SUCCESS);
} /* END MRMSetDefaults() */
int MRMAToString(
mrm_t *R, /* I */
int AIndex, /* I */
char *SVal, /* I */
int Mode) /* I */
{
if ((R == NULL) || (SVal == NULL))
{
return(FAILURE);
}
SVal[0] = '\0';
switch(AIndex)
{
case mrmaAuthType:
if (R->AuthType != 0)
strcpy(SVal,MRMAuthType[R->AuthType]);
break;
case mrmaConfigFile:
/* NYI */
break;
case mrmaEPort:
if (R->EPort > 0)
{
sprintf(SVal,"%d",
R->EPort);
}
break;
case mrmaHost:
if (R->P[0].HostName != NULL)
strcpy(SVal,R->P[0].HostName);
break;
case mrmaLocalDiskFS:
/* NYI */
break;
case mrmaName:
if (R->Name[0] != '\0')
strcpy(SVal,R->Name);
break;
case mrmaNMPort:
if (R->NMPort != 0)
{
/* NOTE: NMPort affect connection to BOTH global node monitor and local node manager */
sprintf(SVal,"%d",
R->NMPort);
}
break;
case mrmaNMServer:
if (R->P[1].HostName != NULL)
strcpy(SVal,R->P[1].HostName);
break;
case mrmaPort:
if (R->P[0].Port > 0)
{
sprintf(SVal,"%d",
R->P[0].Port);
}
break;
case mrmaSocketProtocol:
if (R->P[0].SocketProtocol != mspNONE)
strcpy(SVal,MSockProtocol[R->P[0].SocketProtocol]);
break;
case mrmaSuspendSig:
if (R->SuspendSig[0] != '\0')
strcpy(SVal,R->SuspendSig);
break;
case mrmaTimeout:
if (R->P[0].Timeout > 0)
strcpy(SVal,MULToTString(R->P[0].Timeout));
break;
case mrmaType:
/* FORMAT: <TYPE>[:<SUBTYPE>] */
if (R->Type != mrmtNONE)
{
strcpy(SVal,MRMType[R->Type]);
if (R->SubType != mrmstNONE)
{
sprintf(SVal,"%s:%s",
SVal,
MRMSubType[R->SubType]);
}
} /* END if (R->Type != mrmtNONE) */
break;
case mrmaVersion:
if (R->APIVersion[0] != '\0')
strcpy(SVal,R->APIVersion);
break;
case mrmaWireProtocol:
if (R->P[0].WireProtocol != mwpNONE)
strcpy(SVal,MWireProtocol[R->P[0].WireProtocol]);
break;
default:
/* NO-OP */
break;
} /* END switch(AIndex) */
return(SUCCESS);
} /* END MRMAToString() */
int MRMProcessConfig(
mrm_t *R, /* I */
char *Value) /* I */
{
int aindex;
char *ptr;
char *TokPtr;
char ValLine[MAX_MLINE];
char *ValList[2];
if ((R == NULL) ||
(Value == NULL) ||
(Value[0] == '\0'))
{
return(FAILURE);
}
/* process value line */
ptr = MUStrTok(Value," \t\n",&TokPtr);
while(ptr != NULL)
{
/* parse name-value pairs */
/* FORMAT: <VALUE>[,<VALUE>] */
if (MUGetPair(
ptr,
(const char **)MRMAttr,
&aindex,
NULL,
TRUE,
NULL,
ValLine,
MAX_MNAME) == FAILURE)
{
/* cannot parse value pair */
ptr = MUStrTok(NULL," \t\n",&TokPtr);
continue;
}
ValList[0] = ValLine;
ValList[1] = NULL;
switch(aindex)
{
case mrmaAuthType:
R->AuthType = MUGetIndex(ValLine,MRMAuthType,FALSE,0);
break;
case mrmaConfigFile:
MUStrCpy(R->U.LL.ConfigFile,ValLine,sizeof(R->U.LL.ConfigFile));
break;
case mrmaHost:
MUStrDup(&R->P[0].HostName,ValLine);
break;
case mrmaLocalDiskFS:
MUStrCpy(R->U.PBS.LocalDiskFS,ValLine,sizeof(R->U.PBS.LocalDiskFS));
break;
case mrmaMinETime:
R->EMinTime = MUTimeFromString(ValLine);
break;
case mrmaNMPort:
R->NMPort = (int)strtol(ValLine,NULL,0);
R->P[1].Port = (int)strtol(ValLine,NULL,0);
break;
case mrmaNMServer:
MUStrDup(&R->P[1].HostName,ValLine);
break;
case mrmaPort:
R->P[0].Port = (int)strtol(ValLine,NULL,0);
break;
case mrmaSocketProtocol:
R->P[0].SocketProtocol = MUGetIndex(ValLine,MSockProtocol,FALSE,0);
R->P[1].SocketProtocol = R->P[0].SocketProtocol;
break;
case mrmaSuspendSig:
MRMSetAttr(R,aindex,(void **)ValLine,mdfString,mSet);
break;
case mrmaTimeout:
R->P[0].Timeout = MUTimeFromString(ValLine);
R->P[0].Timeout = MIN(1000,R->P[0].Timeout);
R->P[1].Timeout = R->P[0].Timeout;
break;
case mrmaType:
{
char *ptr;
char *TokPtr;
/* FORMAT: <TYPE>[:<SUBTYPE>] */
ptr = MUStrTok(ValLine,":",&TokPtr);
R->Type = MUGetIndex(ptr,MRMType,FALSE,mrmtNONE);
if ((ptr = MUStrTok(NULL,":",&TokPtr)) != NULL)
{
R->SubType = MUGetIndex(ptr,MRMSubType,FALSE,mrmstNONE);
}
} /* END BLOCK */
break;
case mrmaVersion:
MUStrCpy(R->APIVersion,ValLine,sizeof(R->APIVersion));
break;
case mrmaWireProtocol:
R->P[0].WireProtocol = MUGetIndex(ValLine,MWireProtocol,FALSE,0);
R->P[1].WireProtocol = R->P[0].WireProtocol;
break;
default:
DBG(4,fRM) DPrint("WARNING: RM attribute '%s' not handled\n",
MRMAttr[aindex]);
break;
} /* END switch(aindex) */
ptr = MUStrTok(NULL," \t\n",&TokPtr);
} /* END while (ptr != NULL) */
return(SUCCESS);
} /* END MRMProcessConfig() */
int MRMDestroy(
mrm_t **RP) /* I */
{
mrm_t *R;
if (RP == NULL)
{
return(SUCCESS);
}
R = *RP;
if (R == NULL)
{
return(SUCCESS);
}
/* free dynamic data */
MUFree(&R->P[0].HostName);
MUFree(&R->P[0].CSKey);
MUFree(&R->P[1].HostName);
MUFree(&R->P[1].CSKey);
/* clear structure */
memset(R,0,sizeof(mrm_t));
return(SUCCESS);
} /* END MRMDestroy() */
int MRMCheckConfig(
mrm_t *R) /* I */
{
if (R == NULL)
{
return(FAILURE);
}
/* NYI */
return(SUCCESS);
} /* END MRMCheckConfig() */
int MRMShow(
mrm_t *RP, /* I */
char *Buffer, /* O */
int BufSize, /* I */
int Mode) /* I */
{
int rmindex;
int index;
int findex;
int ShowHeader = TRUE;
int FailureRecorded;
char *BPtr;
int BSpace;
mrm_t *R;
if (Buffer == NULL)
{
return(FAILURE);
}
BPtr = Buffer;
BSpace = BufSize;
BPtr[0] = '\0';
/* NOTE: allow mode to specify verbose, diagnostics, etc */
for (rmindex = 0;MRM[rmindex].Type != mrmtNONE;rmindex++)
{
R = &MRM[rmindex];
if ((RP != NULL) && (RP != R))
continue;
if (ShowHeader == TRUE)
{
ShowHeader = FALSE;
}
MUSNPrintF(&BPtr,&BSpace,"RM[%s] type: '%s' state: '%s'\n",
R->Name,
MRMType[R->Type],
MRMState[R->State]);
/* NOTE: display optional RM version, failures, and fault tolerance config */
if (R->APIVersion[0] != '\0')
{
MUSNPrintF(&BPtr,&BSpace," Version: '%s'\n",
R->APIVersion);
}
if (R->EPort != 0)
{
MUSNPrintF(&BPtr,&BSpace," Event Management: EPORT=%d\n",
R->EPort);
}
else
{
MUSNPrintF(&BPtr,&BSpace," Event Management: (event interface disabled)\n",
R->APIVersion);
}
/* display RM specific attributes */
switch(R->Type)
{
case mrmtPBS:
if (R->U.PBS.PBS5IsEnabled == TRUE)
{
MUSNPrintF(&BPtr,&BSpace," PBSv5 protocol enabled\n");
}
if (R->U.PBS.SSSIsEnabled == TRUE)
{
MUSNPrintF(&BPtr,&BSpace," SSS protocol enabled\n");
}
break;
default:
/* NO-OP */
break;
} /* END switch(R->Type) */
/* NOTE: stats in ms */
if (R->RespTotalCount[0] > 0)
{
MUSNPrintF(&BPtr,&BSpace," RM Performance: Avg Time: %.2lfs Max Time: %.2lfs (%d samples)\n",
(double)R->RespTotalTime[0] / R->RespTotalCount[0] / 1000,
(double)R->RespMaxTime[0] / 1000,
R->RespTotalCount[0]);
}
FailureRecorded = FALSE;
for (index = 0;index < MAX_MRMFAILURE;index++)
{
findex = (index + R->FailIndex) % MAX_MRMFAILURE;
if (R->FailTime[findex] <= 0)
continue;
if (FailureRecorded == FALSE)
{
MUSNPrintF(&BPtr,&BSpace,"\nRM[%s] Failures: \n",
R->Name);
FailureRecorded = TRUE;
}
MUSNPrintF(&BPtr,&BSpace," %19.19s %-15s '%s'\n",
MULToDString((mulong *)&R->FailTime[findex]),
MRMFuncType[R->FailType[findex]],
(R->FailMsg[findex] != NULL) ? R->FailMsg[findex] : "no msg");
} /* END for (index) */
MUSNPrintF(&BPtr,&BSpace,"\n");
} /* END for (rmindex) */
/* NOTE: temp hack. add AM diagnostics to output */
MAMShow(NULL,BPtr,BSpace,Mode);
return(SUCCESS);
} /* END MRMShow() */
int MRMConfigShow(
mrm_t *RP, /* I (optional) */
int Mode, /* I */
char *Buffer, /* O */
int BufSize) /* I */
{
int rmindex;
int aindex;
char tmpLine[MAX_MLINE];
char tmpVal[MAX_MLINE];
mrm_t *R;
char *BPtr;
int BSpace;
const int AList[] = {
mrmaAuthType,
mrmaConfigFile,
mrmaCSAlgo,
mrmaCSKey,
mrmaEPort,
mrmaHost,
mrmaLocalDiskFS,
mrmaMinETime,
mrmaNMPort,
mrmaNMServer,
mrmaPort,
mrmaSocketProtocol,
mrmaSuspendSig,
mrmaTimeout,
mrmaType,
mrmaVersion,
mrmaWireProtocol,
-1 };
const char *FName = "MRMConfigShow";
DBG(6,fSTRUCT) DPrint("%s(%s,%d,%s,%d)\n",
FName,
(RP != NULL) ? "RP" : "NULL",
Mode,
(Buffer != NULL) ? "Buffer" : "NULL",
BufSize);
if (Buffer == NULL)
{
return(FAILURE);
}
BPtr = Buffer;
BSpace = BufSize;
BPtr[0] = '\0';
if (RP == NULL)
{
/* display loaded RM modules */
MUSNPrintF(&BPtr,&BSpace,"# RM MODULES: ");
#if defined(__MLL22) || defined(__MLL31)
MUSNPrintF(&BPtr,&BSpace,"LL ");
#endif /* __MLL22 || __MLL31 */
#ifdef __MLSF
MUSNPrintF(&BPtr,&BSpace,"LSF ");
#endif /* __MLSF */
#ifdef __MPBS
MUSNPrintF(&BPtr,&BSpace,"PBS ");
#endif /* __MPBS */
#ifdef __MRMS
MUSNPrintF(&BPtr,&BSpace,"RMS ");
#endif /* __MRMS */
#ifdef __MSGE
MUSNPrintF(&BPtr,&BSpace,"SGE ");
#endif /* __MSGE */
MUSNPrintF(&BPtr,&BSpace,"SSS ");
MUSNPrintF(&BPtr,&BSpace,"WIKI ");
MUSNPrintF(&BPtr,&BSpace,"NATIVE ");
MUSNPrintF(&BPtr,&BSpace,"\n");
} /* END if (RP == NULL) */
/* NOTE: allow mode to specify verbose, etc */
for (rmindex = 0;rmindex < MAX_MRM;rmindex++)
{
R = &MRM[rmindex];
if ((RP != NULL) && (RP != R))
continue;
tmpLine[0] = '\0';
if (R->Type == mrmtNONE)
continue;
sprintf(tmpLine,"RMCFG[%s]",
R->Name);
for (aindex = 0;AList[aindex] != -1;aindex++)
{
tmpVal[0] = '\0';
MRMAToString(R,AList[aindex],tmpVal,0);
if (tmpVal[0] != '\0')
{
sprintf(tmpLine,"%s %s=%s",
tmpLine,
MRMAttr[AList[aindex]],
tmpVal);
}
} /* END for (aindex) */
MUSNPrintF(&BPtr,&BSpace,"%s\n",
tmpLine);
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMConfigShow() */
int MRMOConfigShow(
mrm_t *RP, /* I */
int VFlag, /* I */
int PIndex, /* I */
char *Buffer) /* O */
{
int rmindex;
mrm_t *R;
mrm_t ZR;
if (Buffer == NULL)
{
return(FAILURE);
}
memset(&ZR,0,sizeof(ZR));
for (rmindex = 0;rmindex < MAX_MRM;rmindex++)
{
R = &MRM[rmindex];
if (!VFlag && (PIndex != -1) && (PIndex != pRMType))
continue;
if (!memcmp(&ZR,R,sizeof(ZR)))
continue;
if ((R->Type == mrmtNONE) && !VFlag)
continue;
if (R->Type == mrmtLL)
{
if ((R->U.LL.ConfigFile[0] != '\0') || (VFlag || (PIndex == -1) || (PIndex == pRMConfigFile)))
strcat(Buffer,MUShowSArray(MParam[pRMConfigFile],rmindex,R->U.LL.ConfigFile));
}
if ((VFlag || (PIndex == -1) || (PIndex == pRMAuthType)))
strcat(Buffer,MUShowSArray(MParam[pRMAuthType],rmindex,(char *)MRMAuthType[R->AuthType]));
strcat(Buffer,"\n");
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMOConfigShow() */
int MRMReqPreLoad(
mreq_t *RQ) /* I */
{
if (RQ == NULL)
{
return(FAILURE);
}
if (RQ->NodeList != NULL)
RQ->NodeList[0].N = NULL;
RQ->MemCmp = mcmpGE;
RQ->DiskCmp = mcmpGE;
RQ->SwapCmp = mcmpGE;
RQ->DRes.Procs = 1;
RQ->DRes.Mem = 0;
RQ->DRes.Disk = 0;
RQ->DRes.Swap = 0;
return(SUCCESS);
} /* END MRMReqPreLoad() */
int MRMJobPreUpdate(
mjob_t *J) /* I */
{
const char *FName = "MRMJobPreUpdate";
DBG(5,fRM) DPrint("%s(%s)\n",
FName,
J->Name);
/* NO-OP */
return(SUCCESS);
} /* END MRMJobPreUpdate() */
int MRMFinalizeCycle()
{
int rc;
int SC;
int rmindex;
mrm_t *R;
for (rmindex = 0;MRM[rmindex].Type != mrmtNONE;rmindex++)
{
R = &MRM[rmindex];
if (MRMFunc[R->Type].CycleFinalize == NULL)
{
DBG(7,fRM) DPrint("INFO: cannot finalize RM cycle (RM '%s' does not support function '%s')\n",
R->Name,
MRMFuncType[mrmCycleFinalize]);
continue;
}
MUThread(
(int (*)(void))*MRMFunc[R->Type].CycleFinalize,
R->P[0].Timeout,
&rc,
2,
NULL,
R,
&SC);
if (rc == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot finalize RM cycle (RM '%s' failed in function '%s')\n",
R->Name,
MRMFuncType[mrmCycleFinalize]);
continue;
}
} /* END for (rmindex) */
return(SUCCESS);
} /* END MRMFinalizeCycle() */
int MRMSetAttr(
mrm_t *R, /* I (modified) */
int AIndex, /* I */
void **Value, /* I */
int Format, /* I */
int Mode) /* I */
{
const char *FName = "MRMSetAttr";
DBG(7,fSCHED) DPrint("%s(%s,%d,Value,%d)\n",
FName,
(R != NULL) ? R->Name : "NULL",
AIndex,
Mode);
if (R == NULL)
{
return(FAILURE);
}
switch(AIndex)
{
case mrmaCSAlgo:
R->P[0].CSAlgo = MUGetIndex((char *)Value,MCSAlgoType,FALSE,R->P[0].CSAlgo);
R->P[1].CSAlgo = MUGetIndex((char *)Value,MCSAlgoType,FALSE,R->P[1].CSAlgo);
break;
case mrmaCSKey:
{
char *ptr;
char *TokPtr;
/* FORMAT: <KEY>[,<KEY>] */
ptr = MUStrTok((char *)Value,",:",&TokPtr);
if (ptr != NULL)
{
MUStrDup(&R->P[0].CSKey,(char *)Value);
ptr = MUStrTok(NULL,",:",&TokPtr);
if (ptr != NULL)
{
MUStrDup(&R->P[1].CSKey,(char *)Value);
}
} /* END if (ptr != NULL) */
} /* END BLOCK */
break;
case mrmaHost:
if (Value != NULL)
strcpy(R->P[0].HostName,(char *)Value);
break;
case mrmaPort:
if (Value != NULL)
{
if (Format == mdfString)
{
R->P[0].Port = (int)strtol((char *)Value,NULL,0);
}
else
{
R->P[0].Port = *(int *)Value;
}
}
break;
case mrmaSuspendSig:
if (Value == NULL)
break;
if (Format == mdfString)
{
MUStrCpy(R->SuspendSig,(char *)Value,sizeof(R->SuspendSig));
}
else
{
sprintf(R->SuspendSig,"%d",
*(int *)Value);
}
break;
default:
/* attribute not handled */
return(FAILURE);
/*NOTREACHED*/
break;
} /* END switch(AIndex) */
return(SUCCESS);
} /* END MRMSetAttr() */
int MRMNodePreLoad(
mnode_t *N, /* I (modified) */
int NState, /* I */
mrm_t *R) /* I */
{
const char *FName = "MRMNodePreLoad";
DBG(5,fRM) DPrint("%s(%s,%s,%s)\n",
FName,
(N != NULL) ? N->Name : "NULL",
MAList[eNodeState][NState],
(R != NULL) ? R->Name : "NULL");
if (N == NULL)
{
return(FAILURE);
}
MSched.EnvChanged = TRUE;
memset(N->FBM,0,sizeof(N->FBM));
N->Network = 0;
N->RM = R;
N->State = NState;
N->TaskCount = 0;
N->EProcCount = 0;
memset(&N->CRes,0,sizeof(N->CRes));
memset(&N->DRes,0,sizeof(N->DRes));
memset(&N->ARes,0,sizeof(N->ARes));
N->DRes.Procs = -1;
N->CRes.Procs = -1;
if (MSched.DefaultN.CRes.Disk > 0)
N->CRes.Disk = MSched.DefaultN.CRes.Disk;
N->ARes.Procs = -1;
N->ARes.Mem = -1;
N->ARes.Swap = -1;
N->ARes.Disk = -1;
N->URes.Procs = -1;
N->ARes.PSlot[0].count = MAX_INT;
/* set default partition */
N->PtIndex = 1;
N->EState = N->State;
N->SyncDeadLine = MAX_MTIME;
N->StateMTime = MSched.Time;
N->R[0] = NULL;
N->CTime = MSched.Time;
N->MTime = MSched.Time;
N->ATime = MSched.Time;
N->STTime = 0;
N->SUTime = 0;
N->SATime = 0;
return(SUCCESS);
} /* END MRMNodePreLoad() */
int MRMNodePostLoad(
mnode_t *N) /* I */
{
mclass_t *C;
char tmpName[MAX_MNAME];
const char *FName = "MRMNodePostLoad";
DBG(5,fRM) DPrint("%s(%s)\n",
FName,
(N != NULL) ? N->Name : "NULL");
if (N == NULL)
{
return(FAILURE);
}
/* load node configuration */
MNodeLoadConfig(N,NULL);
strcpy(tmpName,MNodeAdjustName(N->Name,1));
if (strcmp(N->Name,tmpName) != 0)
MUStrDup(&N->FullName,tmpName);
if (N->CTime == 0)
{
/* initialize node timestamps */
N->CTime = MSched.Time;
N->MTime = MSched.Time;
N->ATime = MSched.Time;
}
/* set default values */
if (N->CRes.Disk == -1)
{
if (MSched.DefaultN.CRes.Disk > 0)
N->CRes.Disk = MSched.DefaultN.CRes.Disk;
else
N->CRes.Disk = 1;
}
if (N->CRes.Mem == -1)
{
if (MSched.DefaultN.CRes.Mem > 0)
N->CRes.Mem = MSched.DefaultN.CRes.Mem;
else
N->CRes.Mem = 1;
}
if (N->CRes.Swap == -1)
{
if (MSched.DefaultN.CRes.Swap > 0)
N->CRes.Swap = MSched.DefaultN.CRes.Swap;
else
N->CRes.Swap = 1;
}
N->CRes.Mem = MAX(N->ARes.Mem,N->CRes.Mem);
if (N->ARes.Mem == -1)
N->ARes.Mem = N->CRes.Mem;
N->CRes.Swap = MAX(N->ARes.Swap,N->CRes.Swap);
if (N->ARes.Swap == -1)
N->ARes.Swap = N->CRes.Swap;
N->CRes.Disk = MAX(N->ARes.Disk,N->CRes.Disk);
if (N->ARes.Disk == -1)
N->ARes.Disk = N->CRes.Disk;
if (N->URes.Procs == -1)
N->URes.Procs = (int)N->Load;
if (memchr(N->CRes.PSlot,'\0',sizeof(N->CRes.PSlot)) == NULL)
{
MClassAdd(DEFAULT,&C);
N->CRes.PSlot[C->Index].count = 1;
N->CRes.PSlot[0].count = 1;
}
/* NOTE: must properly calculate available procs */
if (N->CRes.Procs == -1)
N->CRes.Procs = 1;
if ((MPar[0].NAvailPolicy[0] == mrapUtilized) ||
(MPar[0].NAvailPolicy[0] == mrapCombined))
{
/* use utilized resource info */
if ((MSched.MaxOSCPULoad > 0.0) &&
(N->DRes.Procs == 0) &&
(N->ARes.Procs < N->CRes.Procs))
{
N->ARes.Procs = MAX(0,N->ARes.Procs - (int)(MSched.MaxOSCPULoad * N->CRes.Procs));
}
} /* END if (((MPar[0].NAvailPolicy[pindex] == mrapUtilized) ... */
/* restore checkpoint node information */
MCPRestore(mcpNode,N->Name,(void *)N);
/* connect to existing reservations */
MNodeUpdateResExpression(N);
if (N->ProcSpeed > 0)
MSched.ReferenceProcSpeed = MIN(MSched.ReferenceProcSpeed,N->ProcSpeed);
if (N->Speed <= 0.0)
N->Speed = 1.0;
MNodeGetLocation(N);
if ((N->MaxProcPerClass != NULL) || (MSched.DefaultN.MaxProcPerClass != NULL))
{
int cindex;
int tmpI;
for (cindex = 0;cindex < MAX_MCLASS;cindex++)
{
if (N->CRes.PSlot[cindex].count <= 0)
continue;
if ((N->MaxProcPerClass != NULL) && (N->MaxProcPerClass[cindex] > 0))
{
tmpI = N->MaxProcPerClass[cindex];
}
else if ((MSched.DefaultN.MaxProcPerClass != NULL) &&
(MSched.DefaultN.MaxProcPerClass[cindex] > 0))
{
tmpI = MSched.DefaultN.MaxProcPerClass[cindex];
}
else
{
continue;
}
N->CRes.PSlot[cindex].count = MIN(N->CRes.PSlot[cindex].count,tmpI);
N->CRes.PSlot[cindex].count = MIN(N->CRes.PSlot[cindex].count,tmpI);
} /* END for (cindex) */
} /* END if ((N->MaxProcPerClass != NULL) || ...) */
if ((N->RM == NULL) || (N->RM->Type != mrmtWiki))
{
MNodeResetJobSlots(N);
}
return(SUCCESS);
} /* END MRMNodePostLoad() */
int MRMNodePreUpdate(
mnode_t *N, /* I */
int NState, /* I */
mrm_t *R) /* I */
{
int OldState;
const char *FName = "MRMNodePreUpdate";
DBG(4,fRM) DPrint("%s(%s,%s,%s)\n",
FName,
(N != NULL) ? N->Name : "NULL",
MAList[eNodeState][NState],
(R != NULL) ? R->Name : "NULL");
if (N == NULL)
{
return(FAILURE);
}
/* update node statistics */
N->STTime += MSched.Interval / 100;
if ((N->State != mnsDown) &&
(N->State != mnsNone) &&
(N->State != mnsFlush) &&
(N->State != mnsDraining))
{
N->SUTime += MSched.Interval / 100;
if (N->State != mnsIdle)
{
N->SATime += MSched.Interval / 100;
}
}
/* update node state */
OldState = N->State;
N->State = NState;
/* update node utilization */
memset(&N->DRes,0,sizeof(N->DRes));
N->TaskCount = 0;
N->EProcCount = 0;
if (MSched.Mode == msmSim)
{
/* NO-OP */
}
else
{
N->Load = 0.0;
memset(&N->ARes,0,sizeof(N->ARes));
N->ARes.Procs = -1;
N->ARes.Mem = -1;
N->ARes.Swap = -1;
N->ARes.Disk = -1;
N->ARes.PSlot[0].count = MAX_INT;
}
/* if node state (Busy -> Idle) transition, verify node is Idle */
if (((N->EState == mnsActive) ||
(N->EState == mnsBusy)) &&
(N->State == mnsIdle))
{
/* job completed within a single iteration. synchronize node */
if (MNodeCheckAllocation(N) != SUCCESS)
{
DBG(4,fRM) DPrint("ALERT: node '%s' expected Busy but is Idle and not allocated\n",
N->Name);
N->EState = mnsIdle;
}
else
{
DBG(4,fRM) DPrint("ALERT: node '%s' expected Active but is Idle and allocated\n",
N->Name);
}
}
/* handle node state changes */
if (N->State != OldState)
{
DBG(2,fRM) DPrint("INFO: node '%s' changed states from %s to %s\n",
N->Name,
MAList[eNodeState][OldState],
MAList[eNodeState][N->State]);
MSched.EnvChanged = TRUE;
N->StateMTime = MSched.Time;
/* handle <ANYSTATE> to 'Down/Drain/Flush' state transitions */
if ((N->State == mnsDown) ||
(N->State == mnsDraining) ||
(N->State == mnsDrained) ||
(N->State == mnsFlush))
{
N->EState = N->State;
N->SyncDeadLine = MAX_MTIME;
}
/* handle Down/Drain/Flush state to <any state> transitions */
if ((OldState == mnsDown) ||
(OldState == mnsDraining) ||
(OldState == mnsDrained) ||
(OldState == mnsFlush) ||
(OldState == mnsReserved))
{
N->EState = N->State;
N->SyncDeadLine = MAX_MTIME;
}
if ((OldState == mnsIdle) && (N->State == mnsBusy))
{
if (MSched.Mode != msmTest)
{
DBG(1,fRM) DPrint("ALERT: unexpected node transition on node '%s' Idle -> Busy\n",
N->Name);
}
N->EState = N->State;
N->SyncDeadLine = MAX_MTIME;
}
} /* END if (N->State != OldState) */
return(SUCCESS);
} /* END MRMNodePreUpdate() */
int MRMNodePostUpdate(
mnode_t *N, /* I (modified) */
int OldState) /* I */
{
const char *FName = "MRMNodePostUpdate";
DBG(5,fRM) DPrint("%s(%s,%s)\n",
FName,
(N != NULL) ? N->Name : "NULL",
MNodeState[OldState]);
if (N == NULL)
{
return(FAILURE);
}
N->ATime = MSched.Time;
/* NOTE: assume modification on each iteration */
N->MTime = MSched.Time;
/* set default values */
N->CRes.Mem = MAX(N->ARes.Mem,N->CRes.Mem);
if (N->ARes.Mem == -1)
N->ARes.Mem = N->CRes.Mem;
/* NOTE: attempt to obtain MAX swap over time */
N->CRes.Swap = MAX(N->ARes.Swap,N->CRes.Swap);
if (N->ARes.Swap == -1)
N->ARes.Swap = N->CRes.Swap;
if (N->CRes.Disk == -1)
N->CRes.Disk = 1;
N->CRes.Disk = MAX(N->ARes.Disk,N->CRes.Disk);
if (N->ARes.Disk == -1)
N->ARes.Disk = N->CRes.Disk;
if (N->CRes.Procs == -1)
N->CRes.Procs = 1;
if (N->URes.Procs == -1)
N->URes.Procs = (int)N->Load;
/* NOTE: ARes.Procs and DRes.Procs should be updated in MNodeUpdateState() */
/*
if (N->ARes.Procs == -1)
{
N->ARes.Procs = MAX(0,N->CRes.Procs - N->DRes.Procs);
}
*/
if ((MPar[0].NAvailPolicy[0] == mrapUtilized) ||
(MPar[0].NAvailPolicy[0] == mrapCombined))
{
/* use utilized resource information */
if ((MSched.MaxOSCPULoad > 0.0) &&
(N->DRes.Procs == 0) &&
(N->ARes.Procs < N->CRes.Procs))
{
N->ARes.Procs = MAX(
0,
N->ARes.Procs - (int)(MSched.MaxOSCPULoad * N->CRes.Procs));
}
}
/* unspecifed state, DRes.Procs, and ARes.Procs handled in MNodeUpdateState() */
if ((N->State != N->EState) && (MSched.Time > N->SyncDeadLine))
{
DBG(3,fRM) DPrint("INFO: synchronizing node '%s' to state '%s' (expected state: '%s')\n",
N->Name,
MAList[eNodeState][N->State],
MAList[eNodeState][N->EState]);
N->EState = N->State;
}
/* handle 'down to non-down' state transitions */
if (((OldState == mnsDown) || (OldState == mnsDrained)) &&
(N->State != OldState))
{
MNodeUpdateResExpression(N);
}
if ((N->MaxProcPerClass != NULL) ||
(MSched.DefaultN.MaxProcPerClass != NULL))
{
int cindex;
int tmpI;
for (cindex = 0;cindex < MAX_MCLASS;cindex++)
{
if (N->CRes.PSlot[cindex].count <= 0)
continue;
if ((N->MaxProcPerClass != NULL) && (N->MaxProcPerClass[cindex] > 0))
{
tmpI = N->MaxProcPerClass[cindex];
}
else if ((MSched.DefaultN.MaxProcPerClass != NULL) &&
(MSched.DefaultN.MaxProcPerClass[cindex] > 0))
{
tmpI = MSched.DefaultN.MaxProcPerClass[cindex];
}
else
{
continue;
}
N->CRes.PSlot[cindex].count = MIN(N->CRes.PSlot[cindex].count,tmpI);
} /* END for (cindex) */
} /* END if ((N->MaxProcPerClass != NULL) || ...) */
if ((N->RM == NULL) || (N->RM->Type != mrmtWiki))
{
MNodeResetJobSlots(N);
}
return(SUCCESS);
} /* END MRMNodePostUpdate() */
int MRMJobPreLoad(
mjob_t *J, /* I (modified) */
char *JobName, /* I */
int RMIndex) /* I */
{
const char *FName = "MRMJobPreLoad";
DBG(5,fRM) DPrint("%s(J,%s,%d)\n",
FName,
(JobName != NULL) ? JobName : "NULL",
RMIndex);
if (J == NULL)
{
return(FAILURE);
}
MSched.EnvChanged = TRUE;
J->RM = &MRM[RMIndex];
if (JobName != NULL)
MUStrCpy(J->Name,JobName,sizeof(J->Name));
J->CTime = MSched.Time;
J->MTime = MSched.Time;
J->ATime = MSched.Time;
/* set defaults */
J->CMaxTime = MAX_MTIME;
J->TermTime = MAX_MTIME;
J->Hold = 0;
J->SystemPrio = 0;
J->SyncDeadLine = MAX_MTIME;
J->Bypass = 0;
J->AWallTime = 0;
J->SWallTime = 0;
J->R = NULL;
J->PAL[0] = DEFAULT_MPARLIST;
J->Request.TC = 1;
J->State = mjsIdle;
J->SpecWCLimit[1] = 0;
J->QReq = NULL;
if (J->NodeList != NULL)
J->NodeList[0].N = NULL;
return(SUCCESS);
} /* END MRMJobPreLoad() */
/* NOTE: handling of tasklist information */
/* TaskList[] contains updated task ordering information */
/* must update both J->NodeList and J->Req[X]->NodeList */
/* this call should override, not add to existing info */
int MRMJobPostLoad(
mjob_t *J, /* I (modified) */
short *TaskList, /* I */
mrm_t *R) /* I */
{
int TC;
mqos_t *QDef;
int AccountFallback;
enum MHoldReasonEnum Reason;
int cindex;
int rqindex;
mjob_t *MJ;
mreq_t *RQ;
mnode_t *N;
mgcred_t *A;
char ErrMsg[MAX_MLINE];
char tmpLine[MAX_MLINE];
const char *FName = "MRMJobPostLoad";
DBG(5,fRM) DPrint("%s(%s,TaskList,%s)\n",
FName,
(J != NULL) ? J->Name : "NULL",
(R != NULL) ? R->Name : "NULL");
if ((J == NULL) || (R == NULL))
{
DBG(1,fRM) DPrint("ERROR: invalid job/RM pointer passed to %s()\n",
FName);
return(FAILURE);
}
MTRAPJOB(J,FName);
/* NOTE: determine req/def QOS, allocation status, resulting account/QOS, then create reservation */
if (J->SubmitTime == 0)
{
DBG(1,fRM) DPrint("WARNING: no QueueTime on job '%s'\n",
J->Name);
J->SubmitTime = MSched.Time;
}
AccountFallback = FALSE;
J->SystemQueueTime = J->SubmitTime;
J->EState = J->State;
/* set class cred */
for (cindex = 1;cindex < MAX_MCLASS;cindex++)
{
if (J->Req[0]->DRes.PSlot[cindex].count > 0)
{
J->Cred.C = &MClass[cindex];
break;
}
} /* END for (cindex) */
if (J->Cred.C != NULL)
{
if (J->Cred.C->NonExeType == TRUE)
MJobSetState(J,mjsNotQueued);
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[0];
MUBMOR(RQ->ReqFBM,J->Cred.C->DefFBM,MAX_MATTR);
} /* END for (rqindex) */
}
/* restore checkpointed job status (QOS/Hold/SPrio/Bypass) */
MCPRestore(mcpJob,J->Name,(void *)J);
if ((MQOSGetAccess(J,J->QReq,NULL,&QDef) == FAILURE) ||
(J->QReq == NULL) ||
(J->QReq == &MQOS[0]))
{
MJobSetQOS(J,QDef,0);
}
else
{
MJobSetQOS(J,J->QReq,0);
}
if ((J->SpecWCLimit[1] == 0) || (J->SpecWCLimit[1] == -1))
{
DBG(4,fRM) DPrint("WARNING: wallclock limit not specified for job %s\n",
J->Name);
if ((J->Cred.Q != NULL) &&
(J->Cred.Q->L.JDef != NULL) &&
(((mjob_t *)J->Cred.Q->L.JDef)->SpecWCLimit[0] > 0))
{
J->SpecWCLimit[1] = ((mjob_t *)J->Cred.Q->L.JDef)->SpecWCLimit[0];
}
else if ((J->Cred.C != NULL) &&
(J->Cred.C->L.JDef != NULL) &&
(((mjob_t *)J->Cred.C->L.JDef)->SpecWCLimit[0] > 0))
{
J->SpecWCLimit[1] = ((mjob_t *)J->Cred.C->L.JDef)->SpecWCLimit[0];
}
else
{
J->SpecWCLimit[1] = MPar[0].L.JP->HLimit[mptMaxWC][0];
}
DBG(4,fRM) DPrint("INFO: wallclock limit set to %s on job %s\n",
MULToTString(J->SpecWCLimit[1]),
J->Name);
}
J->SpecWCLimit[0] = J->SpecWCLimit[1];
if ((MPar[0].UseMachineSpeed == FALSE) ||
((J->State != mjsRunning) && (J->State != mjsStarting)))
{
J->WCLimit = J->SpecWCLimit[0];
}
else
{
double tmpD;
MUNLGetMinAVal(J->NodeList,mnaSpeed,NULL,(void *)&tmpD);
if (tmpD > 0.0)
J->WCLimit = (long)((double)J->SpecWCLimit[0] / tmpD);
}
if (MPar[0].EnableMultiNodeJobs == FALSE)
{
J->Req[0]->TasksPerNode = J->Req[0]->TaskCount;
}
/* set tasklist/nodelist */
if (TaskList != NULL)
{
int tindex = 0;
if (J->Req[1] != NULL)
{
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex];
if (RQ->DRes.Procs == 0)
{
/* handle local resources */
MReqAllocateLocalRes(J,RQ);
}
} /* END for (rqindex) */
for (tindex = 0;tindex < MAX_MNODE;tindex++)
{
if (TaskList[tindex] == -1)
break;
} /* END for (tindex) */
MJobGetLocalTL(J,&TaskList[tindex],MAX_MNODE - tindex);
} /* END if (J->Req[1] != NULL) */
if ((J->NodeList == NULL) &&
((J->NodeList = (mnalloc_t *)calloc(1,
sizeof(mnalloc_t) * (MAX_MNODE_PER_JOB + 1))) == NULL))
{
DBG(1,fRM) DPrint("ALERT: cannot allocate memory for job %s nodelist, errno: %d (%s)\n",
J->Name,
errno,
strerror(errno));
return(FAILURE);
}
MUNLFromTL(J->NodeList,TaskList,&J->NodeCount);
memcpy(J->TaskMap,TaskList,sizeof(J->TaskMap));
/* tasklist specified for primary req only */
if (J->Req[0] != NULL)
{
memcpy(
J->Req[0]->NodeList,
J->NodeList,
sizeof(mnalloc_t) * tindex);
J->Req[0]->NodeList[tindex].N = NULL;
}
} /* END if (TaskList != NULL) */
/* check class constraints */
if (MJobCheckClassJLimits(
J,
J->Cred.C,
FALSE,
tmpLine,
sizeof(tmpLine)) == FAILURE)
{
char tmpMsg[MAX_MLINE];
/* job does not meet class constraints */
sprintf(tmpMsg,"job violates class configuration '%s'",
tmpLine);
MJobSetHold(
J,
(1 << mhBatch),
MSched.DeferTime,
mhrPolicyViolation,
tmpLine);
if (J->Req[0] == NULL)
{
/* if sim job removed in set hold */
return(FAILURE);
}
}
/* check account allocation status */
if (MAM[0].FallbackAccount[0] != '\0')
{
if (MAMAllocJReserve(&MAM[0],J,TRUE,&Reason,ErrMsg) == FAILURE)
{
DBG(3,fRM) DPrint("WARNING: cannot reserve allocation for job '%s', reason: %s\n",
J->Name,
MDefReason[Reason]);
if (Reason == mhrNoFunds)
{
DBG(3,fRM) DPrint("WARNING: insufficient allocation in account '%s' to run job '%s' (attempting fallback account '%s')\n",
J->Cred.A->Name,
J->Name,
MAM[0].FallbackAccount);
if (MAcctFind(MAM[0].FallbackAccount,&A) == SUCCESS)
{
J->Cred.A = A;
AccountFallback = TRUE;
}
else
{
DBG(2,fRM) DPrint("ALERT: cannot locate fallback account '%s'\n",
MAM[0].FallbackAccount);
}
}
}
else
{
/* adequate allocations available on primary account, release 'test' bank reservation */
#if !defined(__MQBANK29)
if (MAMAllocResCancel(J->Cred.A->Name,J->Name,"allocation test",NULL,&Reason) == FAILURE)
{
DBG(1,fRM) DPrint("ERROR: cannot cancel allocation reservation for job '%s', reason: %s\n",
J->Name,
MDefReason[Reason]);
}
#endif /* __MQBANK29 */
}
} /* END if (MSched.BankFallbackAccount[0] != '\0') */
/* reset QOS in case fallback account utilized */
if ((MQOSGetAccess(J,J->QReq,NULL,&QDef) == FAILURE) ||
(J->QReq == NULL) ||
(J->QReq == &MQOS[0]))
{
MJobSetQOS(J,QDef,0);
if ((J->QReq != NULL) && (AccountFallback == FALSE))
{
DBG(2,fRM) DPrint("ALERT: job '%s' cannot use requested QOS %s (deferring/setting QOS to default %s)\n",
J->Name,
J->QReq->Name,
QDef->Name);
if (MSched.Mode != msmSim)
{
/* job cannot run in simulation mode w/o admin intervention */
MJobSetHold(
J,
(1 << mhDefer),
MSched.DeferTime,
mhrQOSAccess,
"job cannot use requested QOS");
}
}
}
else
{
MJobSetQOS(J,J->QReq,0);
} /* END else ((MQOSGetAccess(J,J->QReq,NULL,&QDef) == FAILURE) || ... ) */
MJobBuildCL(J);
MJobUpdateFlags(J);
/* determine partition mask */
if (MJobGetPAL(J,J->SpecPAL,J->PAL,NULL) == FAILURE)
{
/* cannot utilize requested PAL */
DBG(2,fRM) DPrint("ALERT: cannot utilize requested PAL '%x'\n",
J->SpecPAL[0]);
}
if (J->Request.TC != J->Req[0]->TaskRequestList[0])
{
J->Request.TC = 0;
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex];
RQ->TaskCount = RQ->TaskRequestList[0];
J->Request.TC += RQ->TaskRequestList[0];
} /* END for (rqindex) */
}
if (J->MasterJobName != NULL)
{
/* locate/update master job */
if (MJobFind(J->MasterJobName,&MJ,0) == FAILURE)
{
DBG(3,fRM) DPrint("ALERT: cannot locate master job '%s' for subjob '%s' (cancelling subjob)\n",
J->MasterJobName,
J->Name);
/* cancel subjob */
MRMJobCancel(J,"MOAB_ERROR: cannot locate parent job\n",NULL);
}
else
{
int sjcount = 0;
for (rqindex = 0;MJ->Req[rqindex] != NULL;rqindex++)
{
if (MJ->Req[rqindex]->RMIndex == R->Index)
{
strcpy(MJ->Req[rqindex]->SubJobName,J->Name);
if (MJ->IState == mjsStaging)
{
MJ->Req[rqindex]->State = mjsStaged;
DBG(3,fRM) DPrint("INFO: located job '%s' subjob[%d] '%s' (RM: %s)\n",
MJ->Name,
rqindex,
J->Name,
R->Name);
}
else
{
DBG(3,fRM) DPrint("ALERT: master job '%s' in state '%s' subjob[%d] '%s' (RM: %s) loaded\n",
MJ->Name,
MAList[eJobState][MJ->State],
rqindex,
J->Name,
R->Name);
}
} /* END if (MJ->Req[index].RMIndex == R->Index) */
if (MJ->Req[rqindex]->State == mjsStaged)
sjcount++;
} /* END for (rqindex) */
if (sjcount == rqindex)
{
if (MJ->IState == mjsStaging)
{
DBG(1,fRM) DPrint("INFO: all subjobs located. starting masterjob '%s'\n",
MJ->Name);
MJ->IState = mjsStaged;
}
}
} /* END else if (MJobFind()) */
} /* END if (J->MasterJobName != NULL) */
else /* (J->MasterJobName != NULL) */
{
if ((J->State == mjsIdle) && (J->EState != mjsDeferred))
{
/* adjust idle job statistics handled in MQueueSelectAllJobs() */
/* NO-OP */
}
else if (MJOBISALLOC(J) == TRUE)
{
double tmpD;
DBG(4,fRM) DPrint("INFO: allocated job '%s' detected\n",
J->Name);
/* setup allocated node count */
if (J->TaskCount == 0)
{
DBG(2,fRM) DPrint("WARNING: job '%s' loaded in allocated state with no tasks allocated\n",
J->Name);
DBG(2,fRM) DPrint("INFO: adjusting allocated procs to %d for job '%s'\n",
MJobGetProcCount(J),
J->Name);
J->TaskCount = J->Request.TC;
}
/* sanity check start time */
J->StartTime = MAX(J->StartTime,J->SubmitTime);
{
long tmpL;
tmpL = J->StartTime + J->SWallTime + J->WCLimit - MSched.Time;
J->RemainingTime = (tmpL > 0) ? tmpL : 0;
} /* END BLOCK */
if (J->AWallTime <= 0)
J->AWallTime = MSched.Time - J->StartTime - J->SWallTime;
else
J->AWallTime = MIN(J->AWallTime,MSched.Time - J->StartTime - J->SWallTime);
/* adjust statistics */
MStatUpdateSubmitJobUsage(J);
/* evaluate allocated nodes */
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
int nindex;
RQ = J->Req[rqindex];
if (RQ->DRes.Procs == 0)
{
MReqAllocateLocalRes(J,RQ);
} /* END if (RQ->DRes.Procs == 0) */
for (nindex = 0;RQ->NodeList[nindex].N != NULL;nindex++)
{
if (RQ->NodeList[nindex].TC == 0)
break;
N = RQ->NodeList[nindex].N;
TC = RQ->NodeList[nindex].TC;
N->TaskCount += TC;
N->EProcCount += TC * RQ->DRes.Procs;
if ((RQ->NAccessPolicy == mnacSingleJob) ||
(RQ->NAccessPolicy == mnacSingleTask))
{
MCResAdd(&N->DRes,&N->CRes,&N->CRes,1,FALSE);
}
else
{
MCResAdd(&N->DRes,&N->CRes,&RQ->DRes,TC,FALSE);
}
} /* END for (nindex) */
/* determine partition */
if ((RQ->PtIndex == 0) && !(J->Flags & (1 << mjfSpan)))
{
if ((RQ->NodeList != NULL) && (RQ->NodeList[0].N != NULL))
RQ->PtIndex = RQ->NodeList[0].N->PtIndex;
else
RQ->PtIndex = 0;
}
} /* END for (rqindex) */
RQ = J->Req[0];
if (J->DispatchTime == 0)
{
DBG(0,fRM) DPrint("ERROR: job '%s' loaded in alloc state '%s' with NULL dispatch time\n",
J->Name,
MJobState[J->State]);
J->DispatchTime = MSched.Time;
/* hack to work around LL API bug */
J->StartTime = J->DispatchTime;
}
MUNLGetMinAVal(J->NodeList,mnaSpeed,NULL,(void **)&tmpD);
if (tmpD > 0.0)
{
J->WCLimit = (int)((double)J->SpecWCLimit[0] / tmpD);
}
if ((RQ->NodeList[0].N == NULL) ||
(RQ->NodeList[0].TC == 0))
memcpy(RQ->NodeList,J->NodeList,sizeof(mnalloc_t) * (MAX_MNODE_PER_JOB + 1));
MResJCreate(J,NULL,J->DispatchTime,mjrActiveJob,NULL);
if (MJOBISACTIVE(J) == TRUE)
{
MQueueAddAJob(J);
}
} /* END else if (MJOBISALLOC(J) == TRUE) */
if (J->Req[1] == NULL)
{
RQ = J->Req[0];
if (J->MReq == NULL)
{
RQ->TaskCount = J->Request.TC;
}
else
{
/* if master node requirements specified */
RQ->TaskCount = J->Request.TC - 1;
}
} /* END if (J->Req[1] == NULL) */
} /* END else (J->MasterName != NULL) */
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex];
RQ->TasksPerNode = MIN(RQ->TasksPerNode,RQ->TaskCount);
if ((RQ->NodeList != NULL) && (RQ->NodeList[0].N != NULL))
{
RQ->PtIndex = RQ->NodeList[0].N->PtIndex;
}
else
{
RQ->PtIndex = 0;
}
} /* END for (rqindex) */
MJobUpdateResourceCache(J,0);
if ((MPar[0].L.JP->HLimit[mptMaxWC][0] > 0) &&
(J->WCLimit > MPar[0].L.JP->HLimit[mptMaxWC][0]))
{
MJobSetHold(
J,
(1 << mhBatch),
MSched.DeferTime,
mhrPolicyViolation,
"job violates system max wclimit");
}
MJobCheckDataReq(J);
if (X.XJobPostInit != (int (*)())0)
{
(*X.XJobPostInit)(X.xd,J,TRUE);
}
RQ = J->Req[0]; /* FIXME */
/* FORMAT: N TR UN GN WC JS UP QT NET OS AR MC MEM DC DSK */
DBG(1,fRM) DPrint("INFO: job '%s' loaded: %3d %8s %8s %6ld %10s %3ld %10ld %8s %6s %6s %2s %6d %2s %6d %s %ld\n",
J->Name,
J->Request.TC,
J->Cred.U->Name,
J->Cred.G->Name,
J->WCLimit,
MJobState[J->State],
J->UPriority,
J->SubmitTime,
MAList[eNetwork][RQ->Network],
MAList[eOpsys][RQ->Opsys],
MAList[eArch][RQ->Arch],
MComp[RQ->MemCmp],
RQ->RequiredMemory,
MComp[RQ->DiskCmp],
RQ->RequiredDisk,
MUMAList(eFeature,RQ->ReqFBM,sizeof(RQ->ReqFBM)),
J->ATime);
DBG(6,fRM) DPrint("INFO: job '%s' size: %d + %d\n",
J->Name,
J->ImageSize,
J->ExecSize);
if (MSched.Mode == msmSim)
{
/* NYI */
}
else if (MSched.Mode == msmNormal)
{
MOSSyslog(LOG_INFO,"new job %s loaded",
J->Name);
}
return(SUCCESS);
} /* END MRMJobPostLoad() */
int MRMJobPostUpdate(
mjob_t *J, /* I (modified) */
short *TaskList, /* I */
enum MJobStateEnum OldState, /* I */
mrm_t *R) /* I */
{
mreq_t *RQ;
int index;
int nindex;
int rqindex;
int tindex;
int jnindex;
int TC;
int SC;
long DeferTime;
mbool_t BuildTaskMap;
int RQ0TC = 0;
int RQ0NC = 0;
mnode_t *N;
char Message[MAX_MLINE << 4];
char tmpLine[MAX_MLINE];
const char *FName = "MRMJobPostUpdate";
DBG(5,fRM) DPrint("%s(%s,TaskList,%s,%s)\n",
FName,
(J != NULL) ? J->Name : "NULL",
MAList[eJobState][OldState],
(R != NULL) ? R->Name : "NULL");
MTRAPJOB(J,FName);
if ((J == NULL) || (R == NULL))
{
return(FAILURE);
}
J->ATime = MSched.Time;
Message[0] = '\0';
if (J->Cred.C != NULL)
{
if (J->Cred.C->NonExeType == TRUE)
MJobSetState(J,mjsNotQueued);
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[0];
MUBMOR(RQ->ReqFBM,J->Cred.C->DefFBM,MAX_MATTR);
} /* END for (rqindex) */
}
MJobUpdateFlags(J);
/* synchronize active job transitions */
if ((J->EState == mjsStarting) && (J->State == mjsRunning))
{
J->EState = mjsRunning;
J->SyncDeadLine = MAX_MTIME;
}
switch(OldState)
{
case mjsSuspended:
J->SWallTime += (long)(MSched.Interval / 100);
break;
case mjsStarting:
case mjsRunning:
if (J->AWallTime <= 0)
{
J->AWallTime = MAX(0,(long)(MSched.Time - J->StartTime - J->SWallTime));
}
else if (MSched.Time > J->StartTime)
{
J->AWallTime += (long)(MSched.Interval / 100);
}
break;
case mjsDeferred:
J->EState = J->State;
J->SyncDeadLine = MAX_MTIME;
break;
case mjsIdle:
case mjsNotQueued:
case mjsHold:
case mjsSystemHold:
if ((J->State == mjsIdle) ||
(J->State == mjsNotQueued) ||
(J->State == mjsHold) ||
(J->State == mjsSystemHold))
{
if (J->EState != mjsDeferred)
{
J->EState = J->State;
J->SyncDeadLine = MAX_MTIME;
}
if ((J->State != OldState) && (J->State == mjsIdle))
{
if (OldState != mjsSystemHold)
J->SystemQueueTime = MSched.Time;
}
}
else if (J->State == mjsRemoved)
{
/* handle cancelled jobs */
DBG(1,fRM) DPrint("ALERT: job '%s' was cancelled externally\n",
J->Name);
return(SUCCESS);
}
break;
default:
/* NO-OP */
break;
} /* END switch (OldState) */
/* determine wclimit */
if (J->SpecWCLimit[1] == 0)
{
DBG(4,fRM) DPrint("WARNING: wallclock limit not specified for job %s\n",
J->Name);
if ((J->Cred.Q != NULL) &&
(J->Cred.Q->L.JDef != NULL) &&
(((mjob_t *)J->Cred.Q->L.JDef)->SpecWCLimit[0] > 0))
{
J->SpecWCLimit[1] = ((mjob_t *)J->Cred.Q->L.JDef)->SpecWCLimit[0];
}
else if ((J->Cred.C != NULL) &&
(J->Cred.C->L.JDef != NULL) &&
(((mjob_t *)J->Cred.C->L.JDef)->SpecWCLimit[0] > 0))
{
J->SpecWCLimit[1] = ((mjob_t *)J->Cred.C->L.JDef)->SpecWCLimit[0];
}
else
{
J->SpecWCLimit[1] = MDEF_SYSJOBWCLIMIT;
}
}
else if (J->SpecWCLimit[1] == (unsigned long)-1)
{
DBG(4,fRM) DPrint("INFO: wallclock limit set to unlimited to job %s\n",
J->Name);
J->SpecWCLimit[1] = MPar[0].L.JP->HLimit[mptMaxWC][0];
}
/*
if (MPar[0].L.JP->HLimit[mptMaxWC][0] > 0)
J->SpecWCLimit[1] = MIN(J->SpecWCLimit[1],MPar[0].L.JP->HLimit[mptMaxWC][0]);
*/
/* check class constraints */
if (MJobCheckClassJLimits(J,J->Cred.C,FALSE,tmpLine,MAX_MLINE) == FAILURE)
{
char tmpMsg[MAX_MLINE];
sprintf(tmpMsg,"job violates class configuration '%s'",
tmpLine);
/* job does not meet class constraints */
MJobSetHold(
J,
(1 << mhBatch),
MSched.DeferTime,
mhrPolicyViolation,
tmpLine);
}
J->SpecWCLimit[0] = J->SpecWCLimit[1];
if ((MPar[0].UseMachineSpeed == FALSE) ||
((J->State != mjsRunning) && (J->State != mjsStarting)))
{
J->WCLimit = J->SpecWCLimit[0];
}
else
{
double tmpD;
MUNLGetMinAVal(J->NodeList,mnaSpeed,NULL,(void **)&tmpD);
if (tmpD > 0.0)
J->WCLimit = (long)((double)J->SpecWCLimit[0] / tmpD);
}
/* adjust active job statistics/state */
if (MJOBISACTIVE(J))
{
J->StartTime = MAX(J->StartTime,J->SubmitTime);
if ((OldState == mjsHold) ||
(OldState == mjsIdle) ||
(OldState == mjsNotRun) ||
(J->NodeList[0].N == NULL))
{
/* build new job list */
J->NodeList[0].N = NULL;
J->TaskMap[0] = -1;
}
else
{
/* check task index ordering */
if (TaskList != NULL)
{
int JobHasMap;
if (J->TaskMap[0] == -1)
JobHasMap = FALSE;
else
JobHasMap = TRUE;
RQ0NC = 0;
RQ0TC = 0;
if (J->Req[1] != NULL)
{
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex];
if (RQ->DRes.Procs == 0)
{
/* handle local resources */
MReqAllocateLocalRes(J,RQ);
}
} /* END for (rqindex) */
for (tindex = 0;tindex < MAX_MNODE;tindex++)
{
if (TaskList[tindex] == -1)
break;
} /* END for (tindex) */
MJobGetLocalTL(J,&TaskList[tindex],MAX_MNODE - tindex);
/* NOTE: must split resources across reqs (NYI) */
RQ0TC = tindex;
} /* END if (J->Req[1] != NULL) */
for (tindex = 0;TaskList[tindex] != -1;tindex++)
{
if (J->TaskMap[tindex] != TaskList[tindex])
{
if (JobHasMap == TRUE)
{
DBG(1,fRM) DPrint("ALERT: task %d changed from '%s' to '%s' for active job '%s'\n",
tindex,
MNode[J->TaskMap[tindex]]->Name,
MNode[TaskList[tindex]]->Name,
J->Name);
}
/* rebuild map */
J->NodeList[0].N = NULL;
J->Req[0]->NodeList[0].N = NULL;
break;
}
} /* END for (tindex) */
} /* END if (TaskList != NULL) */
} /* END else (OldState == jHold) */
if (TaskList != NULL)
{
int SNIndex = 0;
int tmpNC;
int tmpTC;
if (J->NodeList[0].N == NULL)
BuildTaskMap = TRUE;
else
BuildTaskMap = FALSE;
for (tindex = 0;TaskList[tindex] != -1;tindex++)
{
N = MNode[TaskList[tindex]];
if (tindex > MAX_MTASK_PER_JOB)
{
DBG(0,fRM) DPrint("WARNING: job size exceeds internal maximum job size (%d)\n",
MAX_MTASK_PER_JOB);
break;
}
if (BuildTaskMap == TRUE)
{
/* build new node list */
J->TaskMap[tindex] = TaskList[tindex];
for (jnindex = 0;J->NodeList[jnindex].N != NULL;jnindex++)
{
if (J->NodeList[jnindex].N->Index == TaskList[tindex])
{
J->NodeList[jnindex].TC++;
break;
}
} /* END for (jnindex) */
if (J->NodeList[jnindex].N == NULL)
{
J->NodeList[jnindex].N = MNode[TaskList[tindex]];
J->NodeList[jnindex].TC = 1;
J->NodeList[jnindex + 1].N = NULL;
}
} /* END if (BuildTaskMap == TRUE) */
DBG(6,fRM) DPrint("INFO: task %d assigned to job '%s'\n",
tindex,
J->Name);
if (N->State == mnsIdle)
{
DBG(3,fRM) DPrint("ALERT: RM state corruption. job '%s' has idle node '%s' allocated (node forced to active state)\n",
J->Name,
N->Name);
if (Message[0] == '\0')
{
sprintf(Message,"JOBCORRUPTION: job '%s' has the following idle node(s) allocated:\n",
J->Name);
}
if (strlen(Message) + 100 < sizeof(Message))
{
sprintf(Message,"%s '%s' ",
Message,
N->Name);
}
if (N->DRes.Procs >= N->CRes.Procs)
N->EState = mnsBusy;
else
N->EState = mnsActive;
} /* END else if ((OldState == jHold) ... */
} /* END for (tindex) */
/* terminate lists */
if (BuildTaskMap == TRUE)
J->TaskMap[tindex] = -1;
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex + 1];
tmpNC = 0;
tmpTC = 0;
for (nindex = SNIndex;J->NodeList[nindex].TC > 0;nindex++)
{
if (J->NodeList[nindex].N == NULL)
break;
if ((RQ != NULL) &&
(J->NodeList[nindex].N == RQ->NodeList[0].N))
{
break;
}
tmpNC++;
tmpTC += J->NodeList[nindex].TC;
} /* END for (nindex) */
SNIndex = nindex;
J->Req[rqindex]->TaskCount = tmpTC;
J->Req[rqindex]->NodeCount = tmpNC;
} /* END for (rqindex) */
J->NodeList[nindex].N = NULL;
J->NodeCount = nindex;
RQ = J->Req[0]; /* if req info is lost */
if ((RQ->NodeList[0].N == NULL) ||
(RQ->NodeList[0].TC == 0))
{
/* NOTE: address primary req only */
memcpy(
RQ->NodeList,
J->NodeList,
sizeof(mnalloc_t) * (RQ->NodeCount + 1));
}
} /* END if (TaskList != NULL) */
RQ = J->Req[0];
if (J->StartTime == 0)
{
DBG(0,fRM) DPrint("ERROR: job '%s' updated in active state '%s' with NULL start time\n",
J->Name,
MJobState[J->State]);
J->StartTime = MSched.Time;
J->DispatchTime = MSched.Time;
}
J->RemainingTime = (J->WCLimit > J->AWallTime) ?
J->WCLimit - J->AWallTime : 0;
if (J->TaskCount <= 0)
{
DBG(2,fRM) DPrint("WARNING: job '%s' loaded in active state with no tasks allocated\n",
J->Name);
DBG(2,fRM) DPrint("INFO: adjusting allocated tasks for job '%s'\n",
J->Name);
J->TaskCount = J->Request.TC;
if (J->NodeList != NULL)
J->NodeList[0].N = NULL;
if ((RQ != NULL) && (RQ->NodeList != NULL))
RQ->NodeList[0].N = NULL;
} /* END if (J->TaskCount <= 0) */
MQueueAddAJob(J);
/* only make reservation on previously active jobs */
if ((OldState == mjsStarting) || (OldState == mjsRunning))
{
RQ = J->Req[0]; /* FIXME: if req info is lost */
if ((RQ->NodeList[0].N == NULL) ||
(RQ->NodeList[0].TC == 0))
{
memcpy(
RQ->NodeList,
J->NodeList,
sizeof(mnalloc_t) * (MAX_MNODE_PER_JOB + 1));
}
if (J->R != NULL)
{
if (MResCheckJobMatch(J,J->R) == FAILURE)
{
MResDestroy(&J->R);
MResJCreate(J,NULL,J->DispatchTime,mjrActiveJob,NULL);
}
}
else
{
MResJCreate(J,NULL,J->DispatchTime,mjrActiveJob,NULL);
}
}
} /* END if (MJOBISACTIVE(J)) */
else if (J->State == mjsSuspended)
{
RQ = J->Req[0];
if ((RQ->NodeList[0].N == NULL) ||
(RQ->NodeList[0].TC == 0))
{
/* NOTE: address primary req only */
memcpy(
RQ->NodeList,
J->NodeList,
sizeof(mnalloc_t) * (RQ->NodeCount + 1));
}
} /* END else if (J->State == mjsSuspended) */
if (MJOBISACTIVE(J) || MJOBISCOMPLETE(J))
{
if (J->Req[1] != NULL)
{
int rqindex;
J->Request.NC = 0;
J->Request.TC = 0;
J->TaskCount = 0;
J->NodeCount = 0;
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex];
J->Request.NC += RQ->NodeCount;
J->Request.TC += RQ->TaskCount;
if (MJOBISACTIVE(J))
{
J->TaskCount += RQ->TaskCount;
J->NodeCount += RQ->NodeCount;
}
}
} /* END if (J->Req[1] != NULL) */
} /* END if (MJOBISACTIVE(J) || MJOBISCOMPLETE(J)) */
/* adjust completed/removed/vacated job statistics/state */
if (MJOBISCOMPLETE(J))
{
if (J->StartTime == 0)
{
DBG(0,fRM) DPrint("ERROR: Job[%03d] '%s' updated to completed state '%s' with NULL start time\n",
J->Index,
J->Name,
MJobState[J->State]);
/* make best guess */
J->StartTime = MSched.Time;
J->DispatchTime = MSched.Time;
}
if (J->CompletionTime <= J->StartTime)
{
J->CompletionTime = MIN(
MSched.Time,
J->StartTime + J->SWallTime + MAX(J->AWallTime,1));
}
if (J->TaskCount <= 0)
J->TaskCount = J->Request.TC;
} /* END if (MJOBISCOMPLETE(J)) */
/* handle rejected jobs */
if (((J->EState == mjsRunning) ||
(J->EState == mjsStarting)) &&
((J->State == mjsIdle) ||
(J->State == mjsHold)))
{
if (J->Cred.A != NULL)
{
if (MAMAllocResCancel(J->Cred.A->Name,J->Name,"job rejected",NULL,(enum MHoldReasonEnum *)&SC) == FAILURE)
{
DBG(1,fRM) DPrint("ERROR: cannot cancel account reservation for job '%s'\n",
J->Name);
}
}
DeferTime = MSched.DeferTime * (1 + J->StartCount);
J->NodeCount = 0;
J->TaskCount = 0;
J->TaskMap[0] = -1;
DBG(2,fRM) DPrint("ALERT: job '%s' was in state '%s' but is now in state '%s' (job was rejected)\n",
J->Name,
MJobState[J->EState],
MJobState[J->State]);
DBG(2,fRM) DPrint("ALERT: job '%s' is being deferred for %ld seconds\n",
J->Name,
DeferTime);
DBG(4,fRM)
{
DBG(4,fRM) DPrint("INFO: job '%s' nodelist: ",
J->Name);
for (index = 0;index < MAX_MNODE_PER_JOB;index++)
{
if (J->NodeList[index].N == NULL)
break;
fprintf(mlog.logfp,"[%16s]",
J->NodeList[index].N->Name);
} /* END for (index) */
fprintf(mlog.logfp,"\n");
}
MJobSetHold(
J,
(1 << mhDefer),
MSched.DeferTime,
mhrRMReject,
"job rejected by RM");
} /* END if (((J->EState == mjsRunning) || ... */
if (MJOBISACTIVE(J))
{
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex];
for (nindex = 0;RQ->NodeList[nindex].N != NULL;nindex++)
{
N = RQ->NodeList[nindex].N;
TC = RQ->NodeList[nindex].TC;
N->TaskCount += TC;
N->EProcCount += TC * RQ->DRes.Procs;
if ((RQ->NAccessPolicy == mnacSingleJob) ||
(RQ->NAccessPolicy == mnacSingleTask))
{
MCResAdd(&N->DRes,&N->CRes,&N->CRes,1,FALSE);
}
else
{
MCResAdd(&N->DRes,&N->CRes,&RQ->DRes,TC,FALSE);
}
}
} /* END for (rqindex) */
if ((OldState == mjsHold) ||
(OldState == mjsIdle) ||
(OldState == mjsNotRun))
{
MResJCreate(J,NULL,J->DispatchTime,mjrActiveJob,NULL);
}
else
{
/* job was in active state on last iteration */
if ((Message[0] != '\0') &&
(MSched.Time - J->StartTime > 150))
{
/* indicate idle node allocated to active job */
MSysRegEvent(Message,0,0,1);
}
}
} /* END if (MJOBISACTIVE(J)) */
/* handle external job start */
if (((OldState == mjsHold) ||
(OldState == mjsIdle) ||
(OldState == mjsNotRun)) &&
((J->State == mjsRemoved) ||
(J->State == mjsCompleted) ||
(J->State == mjsVacated)))
{
DBG(4,fRM) DPrint("INFO: job '%s' state transition (%s --> %s)\n",
J->Name,
MJobState[OldState],
MJobState[J->State]);
/* if job starts and completes while scheduler is sleeping (cannot happen with x scheduling) */
if (J->EState != mjsRunning)
{
DBG(0,fRM) DPrint("WARNING: scheduler cannot handle completion in 1 iteration on job '%s'\n",
J->Name);
/* set job to active so it can be properly removed */
if (MAMAllocJReserve(&MAM[0],J,FALSE,(enum MHoldReasonEnum *)&SC,Message) == FAILURE)
{
DBG(3,fRM) DPrint("WARNING: cannot create AM reservation for job '%s'\n",
J->Name);
}
MQueueAddAJob(J);
if (J->DispatchTime == 0)
{
if (J->State == mjsCompleted)
{
DBG(0,fRM) DPrint("ERROR: Job[%03d] '%s' updated to completed state '%s' with NULL dispatch time\n",
J->Index,
J->Name,
MJobState[J->State]);
}
J->DispatchTime = MSched.Time;
}
RQ = J->Req[0]; /* if req info is lost */
if ((RQ->NodeList[0].N == NULL) ||
(RQ->NodeList[0].TC == 0))
{
memcpy(RQ->NodeList,J->NodeList,sizeof(mnalloc_t) * (MAX_MNODE_PER_JOB + 1));
}
MResJCreate(J,NULL,J->DispatchTime,mjrActiveJob,NULL);
/* complete job record */
DBG(1,fRM) DPrint("INFO: completing job '%s'\n",
J->Name);
}
} /* END if (((OldState == mjsHold) || ... */
/* check job synchronization */
if (J->State != J->EState)
{
if (MSched.Time > J->SyncDeadLine)
{
/* check if DeferTime is expired */
if (J->EState == mjsDeferred)
{
DBG(2,fRM) DPrint("INFO: restoring job '%s' from deferred state\n",
J->Name);
J->EState = J->State;
J->SyncDeadLine = MAX_MTIME;
if (J->Hold & (1 << mhDefer))
{
J->Hold ^= (1 << mhDefer);
}
J->SystemQueueTime = MSched.Time;
}
}
}
for (rqindex = 0;J->Req[rqindex] != NULL;rqindex++)
{
RQ = J->Req[rqindex];
if ((RQ->NodeList != NULL) && (RQ->NodeList[0].N != NULL))
{
RQ->PtIndex = RQ->NodeList[0].N->PtIndex;
}
else
{
RQ->PtIndex = 0;
}
} /* END for (rqindex) */
RQ = J->Req[0];
/* test mode patch for unexpected state changes */
if ((J->NodeList[0].N == NULL) &&
(RQ->NodeList[0].N != NULL))
{
memcpy(J->NodeList,RQ->NodeList,sizeof(mnalloc_t) * MAX_MNODE_PER_JOB);
}
MJobUpdateResourceCache(J,0);
return(SUCCESS);
} /* END MRMJobPostUpdate() */
int MRMProcessOConfig(
mrm_t *R, /* I (modified) */
int PIndex,
int IVal,
double DVal,
char *SVal,
char **SArray)
{
if (R == NULL)
{
return(FAILURE);
}
switch (PIndex)
{
case pRMPort:
R->P[0].Port = IVal;
break;
case mcoRMEPort:
R->EPort = IVal;
break;
case pRMNMPort:
R->NMPort = IVal;
break;
case pRMTimeout:
R->P[0].Timeout = MUTimeFromString(SVal);
if (R->P[0].Timeout > 1000)
R->P[0].Timeout = 1000;
R->P[1].Timeout = R->P[0].Timeout;
break;
case pRMAuthType:
R->AuthType = MUGetIndex(SVal,MRMAuthType,FALSE,0);
break;
case pRMHost:
MUStrDup(&R->P[0].HostName,SVal);
break;
case pRMName:
/* NOTE: disabled */
/* MUStrCpy(R->Name,SVal,sizeof(R->Name)); */
break;
case pRMType:
{
char *ptr;
char *TokPtr;
/* FORMAT: <TYPE>[:<SUBTYPE>] */
ptr = MUStrTok(SVal,":",&TokPtr);
R->Type = MUGetIndex(ptr,MRMType,FALSE,mrmtNONE);
if ((ptr = MUStrTok(NULL,":",&TokPtr)) != NULL)
{
R->SubType = MUGetIndex(ptr,MRMSubType,FALSE,mrmstNONE);
}
} /* END BLOCK */
break;
case pRMConfigFile:
MUStrCpy(R->U.LL.ConfigFile,SVal,sizeof(R->U.LL.ConfigFile));
break;
case pRMLocalDiskFS:
MUStrCpy(R->U.PBS.LocalDiskFS,SVal,sizeof(R->U.PBS.LocalDiskFS));
break;
default:
/* NO-OP */
break;
} /* END switch(PIndex) */
return(SUCCESS);
} /* END MRMProcessOConfig() */
int MRMSetFailure(
mrm_t *R, /* I */
int FType, /* I */
char *FMsg) /* I */
{
int findex;
if (R == NULL)
{
return(FAILURE);
}
/* record failure */
R->FailCount++;
R->FailIteration = MSched.Iteration;
findex = R->FailIndex;
R->FailTime[findex] = MSched.Time;
R->FailType[findex] = FType;
if (FMsg != NULL)
MUStrDup(&R->FailMsg[findex],FMsg);
else
MUFree(&R->FailMsg[findex]);
R->FailIndex = (findex + 1) % MAX_MRMFAILURE;
/* adjust interface state */
return(SUCCESS);
} /* END MRMSetFailure() */
int __MRMStartFunc(
mrm_t *R, /* I */
int FType) /* I */
{
MUGetMS(NULL,&R->RespStartTime[FType]);
return(SUCCESS);
} /* END __MRMStartFunc() */
int __MRMEndFunc(
mrm_t *R, /* I */
int FType) /* I */
{
long NowMS;
long Interval;
if (R->RespStartTime[FType] <= 0)
{
/* invalid time */
return(FAILURE);
}
MUGetMS(NULL,&NowMS);
if (NowMS < R->RespStartTime[FType])
Interval = R->RespStartTime[FType] - NowMS;
else
Interval = NowMS - R->RespStartTime[FType];
R->RespTotalTime[FType] += Interval;
R->RespMaxTime[FType] = MAX(R->RespMaxTime[FType],Interval);
R->RespTotalCount[FType]++;
if (FType != 0)
{
R->RespTotalTime[0] += Interval;
R->RespMaxTime[0] = MAX(R->RespMaxTime[0],Interval);
R->RespTotalCount[0]++;
}
/* reset start time */
R->RespStartTime[FType] = -1;
return(SUCCESS);
} /* EMD __MRMEndFunc() */
int MNodeResetJobSlots(
mnode_t *N) /* I */
{
int cindex;
mclass_t *C;
if ((N->RM != NULL) && (N->RM->Type == mrmtLL))
{
/* job slots tracked by RM */
return(SUCCESS);
}
N->ARes.PSlot[0].count = 0;
for (cindex = 1;cindex < MAX_MCLASS;cindex++)
{
C = &MClass[cindex];
if ((N->CRes.PSlot[cindex].count > 0) && (C->IsDisabled == FALSE))
{
N->ARes.PSlot[cindex].count = N->CRes.PSlot[cindex].count;
if (C->MaxProcPerNode > 0)
N->ARes.PSlot[cindex].count = MIN(N->ARes.PSlot[cindex].count,C->MaxProcPerNode);
if (N->AP.HLimit[mptMaxProc][0] > 0)
N->ARes.PSlot[cindex].count = MIN(N->ARes.PSlot[cindex].count,N->AP.HLimit[mptMaxProc][0]);
}
else
{
N->ARes.PSlot[cindex].count = 0;
}
N->ARes.PSlot[0].count += N->ARes.PSlot[cindex].count;
} /* END for (cindex) */
N->ARes.PSlot[0].count = MIN(N->CRes.PSlot[0].count,N->ARes.PSlot[0].count);
if (C->MaxProcPerNode > 0)
N->ARes.PSlot[0].count = MIN(N->ARes.PSlot[0].count,C->MaxProcPerNode);
if (N->AP.HLimit[mptMaxProc][0] > 0)
N->ARes.PSlot[0].count = MIN(N->ARes.PSlot[0].count,N->AP.HLimit[mptMaxProc][0]);
return(SUCCESS);
} /* END MNodeResetJobSlots() */
/* END MRM.c */