Browse Source

Merge pull request #9127 from ghalliday/issue15802

HPCC-15802 Add a text stats filter format

Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 8 years ago
parent
commit
64b8ff043b
4 changed files with 102 additions and 15 deletions
  1. 21 10
      dali/daliadmin/daliadmin.cpp
  2. 72 5
      system/jlib/jstats.cpp
  3. 1 0
      system/jlib/jstats.h
  4. 8 0
      system/jlib/jstring.hpp

+ 21 - 10
dali/daliadmin/daliadmin.cpp

@@ -123,7 +123,7 @@ void usage(const char *exe)
   printf("  validatestore [fix=<true|false>]\n"
          "                [verbose=<true|false>]\n"
          "                [deletefiles=<true|false>]-- perform some checks on dali meta data an optionally fix or remove redundant info \n");
-  printf("  stats <workunit> [<creator-type> <creator> <scope-type> <scope> <kind>]\n"
+  printf("  stats <workunit> [<creator-type> <creator> <scope-type> <scope> <kind>|category'['value']',...]\n"
          "                                  -- dump the statistics for a workunit\n");
   printf("  workunit <workunit> [true]      -- dump workunit xml, if 2nd parameter equals true, will also include progress data\n");
   printf("  wuidcompress <wildcard> <type>  --  scan workunits that match <wildcard> and compress resources of <type>\n");
@@ -2530,9 +2530,12 @@ static const char * checkDash(const char * s)
     return s;
 }
 
-static void dumpStats(IConstWorkUnit * workunit, const char * creatorTypeText, const char * creator, const char * scopeTypeText, const char * scope, const char * kindText, bool csv)
+static void dumpStats(IConstWorkUnit * workunit, const char * creatorTypeText, const char * creator, const char * scopeTypeText, const char * scope, const char * kindText, const char * userFilter, bool csv)
 {
     StatisticsFilter filter(checkDash(creatorTypeText), checkDash(creator), checkDash(scopeTypeText), checkDash(scope), NULL, checkDash(kindText));
+    if (userFilter)
+        filter.setFilter(userFilter);
+
     Owned<IConstWUStatisticIterator> stats = &workunit->getStatistics(&filter);
     if (!csv)
         printf("<Statistics wuid=\"%s\">\n", workunit->queryWuid());
@@ -2632,7 +2635,7 @@ static void dumpStats(IConstWorkUnit * workunit, const char * creatorTypeText, c
         printf("</Statistics>\n");
 }
 
-static void dumpStats(const char *wuid, const char * creatorTypeText, const char * creator, const char * scopeTypeText, const char * scope, const char * kindText, bool csv)
+static void dumpStats(const char *wuid, const char * creatorTypeText, const char * creator, const char * scopeTypeText, const char * scope, const char * kindText, const char * userFilter, bool csv)
 {
     Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
     const char * star = strchr(wuid, '*');
@@ -2649,7 +2652,7 @@ static void dumpStats(const char *wuid, const char * creatorTypeText, const char
         {
             Owned<IConstWorkUnit> workunit = factory->openWorkUnit(iter->query().queryWuid());
             if (workunit)
-                dumpStats(workunit, creatorTypeText, creator, scopeTypeText, scope, kindText, csv);
+                dumpStats(workunit, creatorTypeText, creator, scopeTypeText, scope, kindText, userFilter, csv);
         }
     }
     else
@@ -2657,7 +2660,7 @@ static void dumpStats(const char *wuid, const char * creatorTypeText, const char
         Owned<IConstWorkUnit> workunit = factory->openWorkUnit(wuid);
         if (!workunit)
             return;
-        dumpStats(workunit, creatorTypeText, creator, scopeTypeText, scope, kindText, csv);
+        dumpStats(workunit, creatorTypeText, creator, scopeTypeText, scope, kindText, userFilter, csv);
     }
 }
 
@@ -3198,11 +3201,19 @@ int main(int argc, char* argv[])
                         dumpProgress(params.item(1), params.item(2));
                     }
                     else if (stricmp(cmd, "stats") == 0) {
-                        CHECKPARAMS(1,7);
-                        while (params.ordinality() < 7)
-                            params.append("*");
-                        bool csv = params.isItem(7) && strieq(params.item(7), "csv");
-                        dumpStats(params.item(1), params.item(2), params.item(3), params.item(4), params.item(5), params.item(6), csv);
+                        CHECKPARAMS(1, 7);
+                        if ((params.ordinality() >= 3) && (strchr(params.item(2), '[')))
+                        {
+                            bool csv = params.isItem(3) && strieq(params.item(3), "csv");
+                            dumpStats(params.item(1), "-", "-", "-", "-", "-", params.item(2), csv);
+                        }
+                        else
+                        {
+                            while (params.ordinality() < 7)
+                                params.append("*");
+                            bool csv = params.isItem(7) && strieq(params.item(7), "csv");
+                            dumpStats(params.item(1), params.item(2), params.item(3), params.item(4), params.item(5), params.item(6), nullptr, csv);
+                        }
                     }
                     else
                         ERRLOG("Unknown command %s",cmd);

+ 72 - 5
system/jlib/jstats.cpp

@@ -83,7 +83,7 @@ static unsigned matchString(const char * const * names, const char * search)
         const char * next = names[i];
         if (!next)
             return 0;
-        if (streq(next, search))
+        if (strieq(next, search))
             return i;
         i++;
     }
@@ -405,13 +405,27 @@ const char * queryMeasureName(StatisticMeasure measure)
     return measureNames[measure];
 }
 
-StatisticMeasure queryMeasure(const char *  measure)
+StatisticMeasure queryMeasure(const char * measure)
 {
     //MORE: Use a hash table??
     StatisticMeasure ret = (StatisticMeasure)matchString(measureNames, measure);
     //Legacy support for an unusual statistic - pretend the sizes are in bytes instead of kb.
-    if ((ret == SMeasureNone) && measure && streq(measure, "kb"))
-        ret = SMeasureSize;
+    if ((ret == SMeasureNone) && measure)
+    {
+        if (streq(measure, "kb"))
+        {
+            ret = SMeasureSize;
+        }
+        else
+        {
+            for (unsigned i1=SMeasureAll+1; i1 < SMeasureMax; i1++)
+            {
+                const char * prefix = queryMeasurePrefix((StatisticMeasure)i1);
+                if (strieq(measure, prefix))
+                    return (StatisticMeasure)i1;
+            }
+        }
+    }
     return ret;
 }
 
@@ -2249,9 +2263,62 @@ void StatisticsFilter::setCreatorType(StatisticCreatorType _creatorType)
     creatorType = _creatorType;
 }
 
+void StatisticsFilter::addFilter(const char * filter)
+{
+    //Match a filter of the form category[value]  (use square brackets to avoid bash grief)
+    const char * openBra = strchr(filter, '[');
+    if (!openBra)
+        return;
+    const char * closeBra = strchr(openBra, ']');
+    if (!closeBra)
+        return;
+
+    const char * start = openBra + 1;
+    StringBuffer value(closeBra - start, start);
+    if (hasPrefix(filter, "creator[", false))
+        setCreator(value);
+    else if (hasPrefix(filter, "creatortype[", false))
+        setCreatorType(queryCreatorType(value));
+    else if (hasPrefix(filter, "depth[", false))
+    {
+        const char * comma = strchr(value, ',');
+        if (comma)
+            setScopeDepth(atoi(value), atoi(comma+1));
+        else
+            setScopeDepth(atoi(value));
+    }
+    else if (hasPrefix(filter, "kind[", false))
+        setKind(value);
+    else if (hasPrefix(filter, "measure[", false))
+        setMeasure(queryMeasure(value));
+    else if (hasPrefix(filter, "scope[", false))
+        setScope(value);
+    else if (hasPrefix(filter, "scopetype[", false))
+        setScopeType(queryScopeType(value));
+    else
+        throw MakeStringException(1, "Unknown stats filter '%s' - expected creator,creatortype,depth,kind,measure,scope,scopetype", filter);
+}
+
+
 void StatisticsFilter::setFilter(const char * filter)
 {
-    //MORE: Process the filter from a text representation
+    loop
+    {
+        const char * closeBra = strchr(filter, ']');
+        const char * comma = strchr(closeBra, ',');
+        if (comma)
+        {
+            //Take a copy - simplicity rather than efficiency
+            StringBuffer temp(comma - filter, filter);
+            addFilter(temp);
+            filter = comma + 1;
+        }
+        else
+        {
+            addFilter(filter);
+            return;
+        }
+    }
 }
 
 void StatisticsFilter::setScopeDepth(unsigned _scopeDepth)

+ 1 - 0
system/jlib/jstats.h

@@ -230,6 +230,7 @@ public:
     void setMeasure(StatisticMeasure _measure);
 
 protected:
+    void addFilter(const char * filter);
     void init();
 
 protected:

+ 8 - 0
system/jlib/jstring.hpp

@@ -571,6 +571,14 @@ inline bool strieq(const char* s, const char* t) { return stricmp(s,t)==0; }
 inline bool streq(const char* s, const char* t) { return strcmp(s,t)==0; }
 inline bool strsame(const char* s, const char* t) { return (s == t) || (s && t && strcmp(s,t)==0); }  // also allow nulls
 inline bool isEmptyString(const char *text) { return !text||!*text; }
+inline bool hasPrefix(const char * text, const char * prefix, bool caseSensitive)
+{
+    if (caseSensitive)
+        return strncmp(text, prefix, strlen(prefix)) == 0;
+    else
+        return strnicmp(text, prefix, strlen(prefix)) == 0;
+}
+
 
 extern jlib_decl char *j_strtok_r(char *str, const char *delim, char **saveptr);
 extern jlib_decl int j_memicmp (const void *s1, const void *s2, size32_t len);