HTRACE-190. htraced: allowing querying by process id (cmccabe)
diff --git a/htrace-htraced/go/src/org/apache/htrace/common/query.go b/htrace-htraced/go/src/org/apache/htrace/common/query.go
index 8c9128f..aae034c 100644
--- a/htrace-htraced/go/src/org/apache/htrace/common/query.go
+++ b/htrace-htraced/go/src/org/apache/htrace/common/query.go
@@ -81,6 +81,7 @@
 	BEGIN_TIME  Field = "begin"
 	END_TIME    Field = "end"
 	DURATION    Field = "duration"
+	PROCESS_ID  Field = "processid"
 )
 
 func (field Field) IsValid() bool {
@@ -94,7 +95,8 @@
 }
 
 func ValidFields() []Field {
-	return []Field{SPAN_ID, DESCRIPTION, BEGIN_TIME, END_TIME, DURATION}
+	return []Field{SPAN_ID, DESCRIPTION, BEGIN_TIME, END_TIME,
+		DURATION, PROCESS_ID}
 }
 
 type Predicate struct {
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
index 0742555..35c7dad 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/datastore.go
@@ -573,6 +573,10 @@
 		}
 		p.uintKey = s2u64(v)
 		break
+	case common.PROCESS_ID:
+		// Any string is valid for a process ID.
+		p.strKey = pred.Val
+		break
 	default:
 		return nil, errors.New(fmt.Sprintf("Unknown field %s", pred.Field))
 	}
@@ -634,6 +638,8 @@
 		return s2u64(span.End), ""
 	case common.DURATION:
 		return s2u64(span.Duration()), ""
+	case common.PROCESS_ID:
+		return 0, span.ProcessId
 	default:
 		panic(fmt.Sprintf("Field type %s isn't a 64-bit integer.", pred.Field))
 	}
diff --git a/htrace-webapp/src/main/web/app/predicate.js b/htrace-webapp/src/main/web/app/predicate.js
index 87a5602..e48b901 100644
--- a/htrace-webapp/src/main/web/app/predicate.js
+++ b/htrace-webapp/src/main/web/app/predicate.js
@@ -61,6 +61,9 @@
       return val;
     case "spanid":
       return htrace.normalizeSpanId(val);
+    case "processid":
+      htrace.checkStringIsNotEmpty(val);
+      return val;
     default:
       return "Normalization not implemented for field '" + this.field + "'";
     }
@@ -78,6 +81,8 @@
       return "0";
     case "spanid":
       return "";
+    case "processid":
+      return "";
     default:
       return "(unknown)";
     }
@@ -104,6 +109,10 @@
       return new htrace.PType({name: name, field:"duration", op:"le"});
     case "Span ID is":
       return new htrace.PType({name: name, field:"spanid", op:"eq"});
+    case "ProcessId contains":
+      return new htrace.PType({name: name, field:"processid", op:"cn"});
+    case "ProcessId is exactly":
+      return new htrace.PType({name: name, field:"processid", op:"eq"});
     default:
       return null
   }
diff --git a/htrace-webapp/src/main/web/index.html b/htrace-webapp/src/main/web/index.html
index bd15c9a..0e8e6c3 100644
--- a/htrace-webapp/src/main/web/index.html
+++ b/htrace-webapp/src/main/web/index.html
@@ -132,6 +132,10 @@
                         class="add-field">Duration is at most</a></li>
                       <li><a href="javascript:void(0)" 
                         class="add-field">Span ID is</a></li>
+                      <li><a href="javascript:void(0)" 
+                        class="add-field">ProcessId contains</a></li>
+                      <li><a href="javascript:void(0)" 
+                        class="add-field">ProcessId is exactly</a></li>
                     </ul>
                   </div>
                   <button type="submit" class="btn btn-primary" id="searchButton">