Index: /tags/ipp-20100823/dbconfig/pstamp.md
===================================================================
--- /tags/ipp-20100823/dbconfig/pstamp.md	(revision 29289)
+++ /tags/ipp-20100823/dbconfig/pstamp.md	(revision 29290)
@@ -46,4 +46,5 @@
     options     S64         64
     dep_id      S64         0
+    fault_count S32         0
 END
 
@@ -59,4 +60,5 @@
     outdir      STR         255
     fault       S16         0
+    fault_count S32         0
 END
 
Index: /tags/ipp-20100823/ippTools/share/pstamptool_revertdependent.sql
===================================================================
--- /tags/ipp-20100823/ippTools/share/pstamptool_revertdependent.sql	(revision 29289)
+++ /tags/ipp-20100823/ippTools/share/pstamptool_revertdependent.sql	(revision 29290)
@@ -3,4 +3,5 @@
     JOIN pstampRequest USING(req_id)
 SET pstampDependent.fault = 0
+-- fault count hook %s
 WHERE pstampDependent.state = 'new'
     AND (pstampDependent.fault > 0)
Index: /tags/ipp-20100823/ippTools/share/pstamptool_revertjob.sql
===================================================================
--- /tags/ipp-20100823/ippTools/share/pstamptool_revertjob.sql	(revision 29289)
+++ /tags/ipp-20100823/ippTools/share/pstamptool_revertjob.sql	(revision 29290)
@@ -2,4 +2,5 @@
     JOIN pstampRequest USING(req_id)
 SET pstampJob.fault = 0
+ -- clear fault count clause goes here %s
 WHERE  pstampRequest.state = 'run'
     AND pstampJob.state = 'run'
Index: /tags/ipp-20100823/ippTools/src/pstamptool.c
===================================================================
--- /tags/ipp-20100823/ippTools/src/pstamptool.c	(revision 29289)
+++ /tags/ipp-20100823/ippTools/src/pstamptool.c	(revision 29290)
@@ -46,4 +46,5 @@
 static bool pendingjobMode(pxConfig *config);
 static bool updatejobMode(pxConfig *config);
+static bool stopdependentjobMode(pxConfig *config);
 static bool revertjobMode(pxConfig *config);
 static bool addprojectMode(pxConfig *config);
@@ -63,4 +64,7 @@
     break;
 
+// XXX make this a configurable parameter
+#define PSTAMP_MAX_JOB_FAULTS 5
+#define PSTAMP_MAX_DEP_FAULTS 5
 
 int main(int argc, char **argv)
@@ -89,4 +93,5 @@
         MODECASE(PSTAMPTOOL_MODE_PENDINGJOB, pendingjobMode);
         MODECASE(PSTAMPTOOL_MODE_UPDATEJOB, updatejobMode);
+        MODECASE(PSTAMPTOOL_MODE_STOPDEPENDENTJOB, stopdependentjobMode);
         MODECASE(PSTAMPTOOL_MODE_REVERTJOB, revertjobMode);
         MODECASE(PSTAMPTOOL_MODE_ADDPROJECT, addprojectMode);
@@ -715,5 +720,6 @@
             outputBase,
             options,
-            dep_id
+            dep_id,
+            0   // fault_count
             )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -909,4 +915,5 @@
         psStringAppend(&query, "\n %c pstampJob.fault = %d", c, fault);
         c = ',';
+        psStringAppend(&query, ", pstampJob.fault_count = pstampJob.fault_count+ 1");
     }
     
@@ -925,4 +932,45 @@
     psU64 affected = psDBAffectedRows(config->dbh);
     psLogMsg("pstamptool", PS_LOG_INFO, "Updated %" PRIu64 " pstampJobs", affected);
+
+    return true;
+}
+// Terminate jobs which have dependents setting both the pstampDependent and pstampJob.fault
+static bool stopdependentjobMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S32(fault,  config->args, "-set_fault",  true, false);
+
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_S64(config->args, where, "-req_id", "req_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-job_id", "job_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-dep_id", "dep_id", "==");
+    PXOPT_COPY_S32(config->args, where, "-fault",  "pstampDependent.fault", "==");
+
+    // XXX: How about selecting by pstampRequest.label? No. That is too dangerous by itself.
+
+    psString query = pxDataGet("pstamptool_stopdependentjob.sql");
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    } else {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+    psFree(where);
+
+    if (!p_psDBRunQueryF(config->dbh, query, fault, fault)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psU64 affected = psDBAffectedRows(config->dbh);
+    psLogMsg("pstamptool", PS_LOG_INFO, "Updated %" PRIu64 " pstampJobs and pstampDependents", affected);
 
     return true;
@@ -941,5 +989,8 @@
     pxAddLabelSearchArgs(config, where, "-label", "pstampRequest.label", "LIKE");
 
+    PXOPT_LOOKUP_BOOL(clear_fault_count, config->args, "-clear_fault_count", false);
+
     PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
+
     // XXX: we don't actually use -limit. It doesn't work for UPDATE
     // it's an allowed arg because add_poll_args adds it
@@ -949,5 +1000,5 @@
     // By default only revert faults < PSTAMP_FIRST_ERROR_CODE which are our "ipp exit codes"
     // codes larger than that are the pstamp request interface.
-    // Don't fault those unless -fault waa provided
+    // Don't fault those unless -fault was explicitly provided
     psString faultClause = psStringCopy("");
     if (!fault) {
@@ -968,5 +1019,15 @@
     psFree(where);
 
-    if (!p_psDBRunQueryF(config->dbh, query, faultClause)) {
+    // don't keep reverting once the number of faults reaches some value unless 
+    // a parameter asking us to clear that count is provided
+    psString faultCountClause = NULL;
+    if (clear_fault_count) {
+        psStringAppend(&faultCountClause, "\n, pstampJob.fault_count = 0");
+    } else {
+        psStringAppend(&query, " AND pstampJob.fault_count < %d", PSTAMP_MAX_JOB_FAULTS);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, faultCountClause, faultClause)) {
+        psFree(faultCountClause);
         psFree(faultClause);
         psFree(query);
@@ -976,4 +1037,6 @@
 
     psFree(faultClause);
+    psFree(faultCountClause);
+    psFree(query);
 
     return true;
@@ -1180,5 +1243,6 @@
         need_magic,
         outdir,
-        0               // fault
+        0,              // fault
+        0               // fault_count
         )) {
         if (!psDBRollback(config->dbh)) {
@@ -1302,4 +1366,5 @@
         psStringAppend(&query, "%s fault = %d", needComma ? ", " : "", fault);
         needComma = true;
+        psStringAppend(&query, ", pstampDependent.fault_count = pstampDependent.fault_count + 1");
     }
     psStringAppend(&query, " WHERE dep_id = %" PRId64, dep_id);
@@ -1327,5 +1392,8 @@
     PXOPT_COPY_S64(config->args, where, "-fault", "pstampDependent.fault", "==");
     PXOPT_COPY_S64(config->args, where, "-dep_id", "dep_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-job_id", "job_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-req_id", "req_id", "==");
     pxAddLabelSearchArgs(config, where, "-label", "pstampRequest.label", "==");
+    PXOPT_LOOKUP_BOOL(clear_fault_count, config->args, "-clear_fault_count", false);
 
     // XXX: we don't actually use -limit. It doesn't work for UPDATE
@@ -1358,5 +1426,15 @@
     }
 
-    if (!p_psDBRunQuery(config->dbh, query)) {
+    // don't keep reverting once the number of faults reaches some value unless 
+    // a parameter asking us to clear that count is provided
+    psString faultCountClause = NULL;
+    if (clear_fault_count) {
+        psStringAppend(&faultCountClause, "\n, pstampDependent.fault_count = 0");
+    } else {
+        psStringAppend(&faultCountClause, " ");
+        psStringAppend(&query, " AND pstampDependent.fault_count < %d", PSTAMP_MAX_DEP_FAULTS);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, faultCountClause)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
Index: /tags/ipp-20100823/ippTools/src/pstamptoolConfig.c
===================================================================
--- /tags/ipp-20100823/ippTools/src/pstamptoolConfig.c	(revision 29289)
+++ /tags/ipp-20100823/ippTools/src/pstamptoolConfig.c	(revision 29290)
@@ -170,4 +170,12 @@
     psMetadataAddS16(updatejobArgs, PS_LIST_TAIL, "-set_fault", 0,            "new result", 0);
 
+    // -stopdependentjob
+    psMetadata *stopdependentjobArgs = psMetadataAlloc();
+    psMetadataAddS64(stopdependentjobArgs, PS_LIST_TAIL,  "-req_id", 0,       "req_id of jobs to update", 0);
+    psMetadataAddS64(stopdependentjobArgs, PS_LIST_TAIL,  "-job_id", 0,       "job_id of jobs to update", 0);
+    psMetadataAddS64(stopdependentjobArgs, PS_LIST_TAIL,  "-dep_id", 0,       "dep_id of jobs to update", 0);
+    psMetadataAddS16(stopdependentjobArgs, PS_LIST_TAIL,  "-fault", 0,        "current value for dependent fault", 0);
+    psMetadataAddS16(stopdependentjobArgs, PS_LIST_TAIL,  "-set_fault", 0,    "new fault value for job and dependent (required)", 0);
+
     // -revertjob
     psMetadata *revertjobArgs = psMetadataAlloc();
@@ -177,4 +185,5 @@
     psMetadataAddS16(revertjobArgs, PS_LIST_TAIL, "-fault",  0,     "fault to revert", 0);
     psMetadataAddStr(revertjobArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by pstampRequest label (LIKE comparision)", NULL);
+    psMetadataAddBool(revertjobArgs, PS_LIST_TAIL, "-clear_fault_count", 0,       "clear job fault count", false);
     psMetadataAddBool(revertjobArgs, PS_LIST_TAIL, "-all", 0,       "revert all faulted jobs", false);
     psMetadataAddU64(revertjobArgs, PS_LIST_TAIL, "-limit", 0,      "limit result set to N items", 0);
@@ -201,8 +210,11 @@
     // -revertdependent
     psMetadata *revertdependentArgs = psMetadataAlloc();
-    psMetadataAddS64(revertdependentArgs, PS_LIST_TAIL, "-dep_id", 0, "define id for dependent", 0);
+    psMetadataAddS64(revertdependentArgs, PS_LIST_TAIL, "-dep_id", 0, "search by dep_id for dependent", 0);
+    psMetadataAddS64(revertdependentArgs, PS_LIST_TAIL, "-job_id", 0, "search by job_ idfor dependent", 0);
+    psMetadataAddS64(revertdependentArgs, PS_LIST_TAIL, "-req_id", 0, "search by req_id for dependent", 0);
     psMetadataAddStr(revertdependentArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK,   "define label for dependent ", NULL);
-    psMetadataAddS16(revertdependentArgs, PS_LIST_TAIL, "-fault",  0,   "define fault", 0);
-    psMetadataAddU64(revertdependentArgs, PS_LIST_TAIL, "-limit", 0,      "limit result set to N items", 0);
+    psMetadataAddS16(revertdependentArgs, PS_LIST_TAIL, "-fault",  0, "search by dependent fault", 0);
+    psMetadataAddBool(revertdependentArgs, PS_LIST_TAIL, "-clear_fault_count", 0,       "clear job fault count", false);
+    psMetadataAddU64(revertdependentArgs, PS_LIST_TAIL, "-limit", 0,  "limit result set to N items", 0);
 
     // -pendingdependent
@@ -263,4 +275,5 @@
     PXOPT_ADD_MODE("-pendingjob",      "", PSTAMPTOOL_MODE_PENDINGJOB,   pendingjobArgs);
     PXOPT_ADD_MODE("-updatejob",       "", PSTAMPTOOL_MODE_UPDATEJOB,    updatejobArgs);
+    PXOPT_ADD_MODE("-stopdependentjob", "", PSTAMPTOOL_MODE_STOPDEPENDENTJOB,  stopdependentjobArgs);
     PXOPT_ADD_MODE("-revertjob",       "", PSTAMPTOOL_MODE_REVERTJOB,    revertjobArgs);
 
