Issue #2579 Make DecisionTree thread safe.
Change-Id: I351135189c58ba5a6107de206f8f5dc2d72fc8c0 Former-commit-id:fea2532ea7
[formerlyb92f9efb53
] [formerlyb096554d97
[formerly 345316581c514136c823692a09ff0d71ce5b7877]] Former-commit-id:b096554d97
Former-commit-id:0d1898a070
This commit is contained in:
parent
eee649c9b1
commit
1dc5fcd852
9 changed files with 136 additions and 119 deletions
|
@ -28,6 +28,8 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
|
||||
|
@ -43,12 +45,15 @@ import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintTyp
|
|||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jul 3, 2007 chammack Initial Creation.
|
||||
* Jan 14, 2013 1442 rferrel Added method searchTreeUsingContraints.
|
||||
* Addition checks on constraints.
|
||||
* May 28, 2013 1638 mschenke Added proper support for {@link ConstraintType#ISNULL}
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- -----------------------------------------
|
||||
* Jul 03, 2007 chammack Initial Creation.
|
||||
* Jan 14, 2013 1442 rferrel Added method searchTreeUsingContraints.
|
||||
* Addition checks on constraints.
|
||||
* May 28, 2013 1638 mschenke Added proper support for
|
||||
* {@link ConstraintType#ISNULL}
|
||||
* Dec 18, 2013 2579 bsteffen Replace synchronization with a
|
||||
* read/write lock.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -94,9 +99,7 @@ public class DecisionTree<T> {
|
|||
if (lvl == 0) {
|
||||
// heuristic: Always start with pluginName
|
||||
entropyPair = new EntropyPair[1];
|
||||
entropyPair[0] = new EntropyPair();
|
||||
entropyPair[0].attribute = "pluginName";
|
||||
entropyPair[0].entropy = 1.0f;
|
||||
entropyPair[0] = new EntropyPair("pluginName", 1.0f);
|
||||
} else {
|
||||
for (String attrib : localAttribList) {
|
||||
// For an attribute, pull out the possible values
|
||||
|
@ -133,9 +136,8 @@ public class DecisionTree<T> {
|
|||
Iterator<String> attributeListIter = localAttribList.iterator();
|
||||
|
||||
for (int i = 0; attributeListIter.hasNext(); i++) {
|
||||
entropyPair[i] = new EntropyPair();
|
||||
entropyPair[i].attribute = attributeListIter.next();
|
||||
entropyPair[i].entropy = entropyValues.get(i);
|
||||
entropyPair[i] = new EntropyPair(attributeListIter.next(),
|
||||
entropyValues.get(i));
|
||||
}
|
||||
|
||||
Arrays.sort(entropyPair);
|
||||
|
@ -225,22 +227,25 @@ public class DecisionTree<T> {
|
|||
}
|
||||
|
||||
protected class DataPair {
|
||||
public Map<String, RequestConstraint> metadata;
|
||||
public final Map<String, RequestConstraint> metadata;
|
||||
|
||||
public final T data;
|
||||
|
||||
public DataPair(Map<String, RequestConstraint> metadata, T data) {
|
||||
this.metadata = metadata;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public T data;
|
||||
}
|
||||
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
private final List<DataPair> dataPairs;
|
||||
|
||||
private final Set<String> attributes;
|
||||
|
||||
private Node head;
|
||||
|
||||
private int size = 0;
|
||||
|
||||
public DecisionTree() {
|
||||
dataPairs = new ArrayList<DataPair>();
|
||||
attributes = new HashSet<String>();
|
||||
}
|
||||
|
||||
public void insertCriteria(Map<String, RequestConstraint> searchCriteria,
|
||||
|
@ -249,25 +254,22 @@ public class DecisionTree<T> {
|
|||
throw new IllegalArgumentException(
|
||||
"Search criteria must not be null");
|
||||
|
||||
// Check for the case that the item is already listed
|
||||
DataPair e = new DataPair();
|
||||
e.data = item;
|
||||
e.metadata = searchCriteria;
|
||||
this.dataPairs.add(e);
|
||||
size++;
|
||||
DataPair e = new DataPair(searchCriteria, item);
|
||||
|
||||
Set<String> keys = searchCriteria.keySet();
|
||||
|
||||
this.attributes.addAll(keys);
|
||||
|
||||
if (rebuild) {
|
||||
// Now, trigger a tree rebuild
|
||||
rebuildTree();
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
this.dataPairs.add(e);
|
||||
if (rebuild) {
|
||||
rebuildTree();
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void rebuildTree() {
|
||||
synchronized (this) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (this.dataPairs.size() == 0) {
|
||||
this.head = null;
|
||||
return;
|
||||
|
@ -275,6 +277,8 @@ public class DecisionTree<T> {
|
|||
|
||||
this.head = new Node();
|
||||
this.head.rebuildTree(dataPairs, new ArrayList<String>(), 0);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +322,8 @@ public class DecisionTree<T> {
|
|||
*/
|
||||
private List<T> searchTree(Map<String, ?> searchCriteria,
|
||||
boolean evaluateConstraints) {
|
||||
synchronized (this) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
List<T> lst = new ArrayList<T>();
|
||||
if (head == null) {
|
||||
return lst;
|
||||
|
@ -328,6 +333,8 @@ public class DecisionTree<T> {
|
|||
|
||||
searchTree(curNode, searchCriteria, lst, 0, evaluateConstraints);
|
||||
return lst;
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,8 +398,10 @@ public class DecisionTree<T> {
|
|||
* @param item
|
||||
*/
|
||||
public void remove(T item) {
|
||||
boolean itemRemoved = false;
|
||||
synchronized (this) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
boolean itemRemoved = false;
|
||||
|
||||
// This could be optimized but removes are a very uncommon operation
|
||||
Iterator<DataPair> exampleIterator = dataPairs.iterator();
|
||||
while (exampleIterator.hasNext()) {
|
||||
|
@ -404,39 +413,26 @@ public class DecisionTree<T> {
|
|||
itemRemoved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (itemRemoved) {
|
||||
rebuildTree();
|
||||
}
|
||||
}
|
||||
|
||||
public void traverse() {
|
||||
System.out.println("Head:");
|
||||
traverse(head);
|
||||
|
||||
}
|
||||
|
||||
public void traverse(Node n) {
|
||||
if (n == null)
|
||||
return;
|
||||
System.out.println(n.type);
|
||||
if (n.type == NodeType.LEAF) {
|
||||
System.out.println(n.values);
|
||||
} else if (n.type == NodeType.DECISION) {
|
||||
System.out.println(n.decision);
|
||||
}
|
||||
System.out.println(n.decisionAttribute);
|
||||
System.out.println("-------");
|
||||
|
||||
for (int i = 0; i < n.nodeChildren.size(); i++) {
|
||||
System.out.println("Child of: " + n.decisionAttribute + " " + i);
|
||||
Node n2 = n.nodeChildren.get(i);
|
||||
traverse(n2);
|
||||
if (itemRemoved) {
|
||||
rebuildTree();
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected List<DataPair> getDataPairs() {
|
||||
return new ArrayList<DecisionTree<T>.DataPair>(dataPairs);
|
||||
/*
|
||||
* Copy dataPairs to avoid external iterators getting concurrent
|
||||
* modification. Must get read lock because copying iterates over
|
||||
* dataPairs.
|
||||
*/
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return new ArrayList<DataPair>(dataPairs);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static double calcEntropy(int numExamples, Integer[] values) {
|
||||
|
@ -451,9 +447,14 @@ public class DecisionTree<T> {
|
|||
}
|
||||
|
||||
private static class EntropyPair implements Comparable<EntropyPair> {
|
||||
public String attribute;
|
||||
public final String attribute;
|
||||
|
||||
public double entropy;
|
||||
public final double entropy;
|
||||
|
||||
public EntropyPair(String attribute, double entropy) {
|
||||
this.attribute = attribute;
|
||||
this.entropy = entropy;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import com.raytheon.uf.common.serialization.ISerializableObject;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
|
||||
|
@ -35,16 +34,18 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
|||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 11/07/08 #1673 bphillip Initial Creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Nov 07, 2008 1673 bphillip Initial Creation
|
||||
* Dec 18, 2013 2579 bsteffen Remove ISerializableObject
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
* @version 1.0
|
||||
*/
|
||||
@DynamicSerialize
|
||||
public class QueryResult implements ISerializableObject {
|
||||
public class QueryResult {
|
||||
|
||||
/** A mapping of the column names to their index in the result */
|
||||
@DynamicSerializeElement
|
||||
|
@ -167,12 +168,10 @@ public class QueryResult implements ISerializableObject {
|
|||
*/
|
||||
public String[] getColumnNameArray() {
|
||||
String[] names = new String[columnNames.size()];
|
||||
int i = 0;
|
||||
for (Iterator<String> it = columnNames.keySet().iterator(); it
|
||||
.hasNext();) {
|
||||
String key = it.next();
|
||||
names[columnNames.get(key)] = key;
|
||||
i++;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ package com.raytheon.uf.common.dataquery.db;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.raytheon.uf.common.serialization.ISerializableObject;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
|
||||
|
@ -31,16 +30,18 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
|||
*
|
||||
* <pre>
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 11/07/08 #1673 bphillip Initial Creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Nov 07, 2008 1673 bphillip Initial Creation
|
||||
* Dec 18, 2013 2579 bsteffen Remove ISerializableObject
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
* @version 1.0
|
||||
*/
|
||||
@DynamicSerialize
|
||||
public class QueryResultRow implements ISerializableObject {
|
||||
public class QueryResultRow {
|
||||
|
||||
/**
|
||||
* The values of the returned columns
|
||||
|
|
|
@ -24,20 +24,24 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
|||
import com.raytheon.uf.common.serialization.comm.IServerRequest;
|
||||
|
||||
/**
|
||||
* TODO Add Description
|
||||
* Send multiple {@link DbQueryRequestSet}s at once. This can be more efficient
|
||||
* than sending multiple requests individually because it reduces the network
|
||||
* overhead.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 30, 2011 rjpeter Initial creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Jun 30, 2011 rjpeter Initial creation
|
||||
* Dec 18, 2013 2579 bsteffen Class javadoc
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rjpeter
|
||||
* @version 1.0
|
||||
* @see DbQueryRequest
|
||||
*/
|
||||
@DynamicSerialize
|
||||
public class DbQueryRequestSet implements IServerRequest {
|
||||
|
|
|
@ -21,7 +21,6 @@ package com.raytheon.uf.common.dataquery.requests;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.raytheon.uf.common.serialization.ISerializableObject;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
import com.raytheon.uf.common.serialization.comm.IServerRequest;
|
||||
|
@ -32,9 +31,10 @@ import com.raytheon.uf.common.serialization.comm.IServerRequest;
|
|||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb 16, 2011 #8070 ekladstrup Initial creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Feb 16, 2011 8070 ekladstrup Initial creation
|
||||
* Dec 18, 2013 2579 bsteffen Remove ISerializableObject
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -42,7 +42,7 @@ import com.raytheon.uf.common.serialization.comm.IServerRequest;
|
|||
* @version 1.0
|
||||
*/
|
||||
@DynamicSerialize
|
||||
public class QlServerRequest implements IServerRequest, ISerializableObject {
|
||||
public class QlServerRequest implements IServerRequest {
|
||||
|
||||
@DynamicSerializeElement
|
||||
private Map<String, RequestConstraint> rcMap;
|
||||
|
|
|
@ -40,29 +40,31 @@ import javax.xml.bind.annotation.XmlAttribute;
|
|||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import com.raytheon.uf.common.serialization.ISerializableObject;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
import com.raytheon.uf.common.time.util.TimeUtil;
|
||||
|
||||
/**
|
||||
* RequestConstraint - Constraints on a uEngine request
|
||||
*
|
||||
* Allows non-equals style constraints
|
||||
* Used in requests to limit the type of data returned. Similar to an sql WHERE
|
||||
* clause, it consists of a type(operator) and a value. When a request is made
|
||||
* fields will be compared to the constraint value with the specified type to
|
||||
* determine what data to return.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 21, 2007 chammack Initial Creation.
|
||||
* May 27, 2009 2408 jsanchez Cast value to String.
|
||||
* Sep 28, 2009 3099 bsteffen Fixed constraintCompare to convert
|
||||
* all non-numeric objects to String
|
||||
* Nov 05, 2009 3553 rjpeter Added isNull capability.
|
||||
* Jul 09, 2013 1869 bsteffen Format Calendar when making
|
||||
* Constraint Mapping.
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- -----------------------------------------
|
||||
* Aug 21, 2007 chammack Initial Creation.
|
||||
* May 27, 2009 2408 jsanchez Cast value to String.
|
||||
* Sep 28, 2009 3099 bsteffen Fixed constraintCompare to convert all
|
||||
* non-numeric objects to String
|
||||
* Nov 05, 2009 3553 rjpeter Added isNull capability.
|
||||
* Jul 09, 2013 1869 bsteffen Format Calendar when making Constraint
|
||||
* Mapping.
|
||||
* Dec 18, 2013 2579 bsteffen Remove ISerializableObject
|
||||
*
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -73,7 +75,7 @@ import com.raytheon.uf.common.time.util.TimeUtil;
|
|||
@XmlRootElement(name = "requestConstraint")
|
||||
@XmlType(name = "requestConstraint")
|
||||
@DynamicSerialize
|
||||
public class RequestConstraint implements ISerializableObject, Cloneable {
|
||||
public class RequestConstraint implements Cloneable {
|
||||
|
||||
public static final RequestConstraint WILDCARD;
|
||||
static {
|
||||
|
@ -114,7 +116,8 @@ public class RequestConstraint implements ISerializableObject, Cloneable {
|
|||
@DynamicSerializeElement
|
||||
protected String constraintValue;
|
||||
|
||||
protected transient Map<Class<?>, Object> asMap = new HashMap<Class<?>, Object>();
|
||||
protected transient Map<Class<?>, Object> asMap = new HashMap<Class<?>, Object>(
|
||||
2);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
|
|
@ -24,20 +24,25 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
|||
import com.raytheon.uf.common.serialization.comm.IServerRequest;
|
||||
|
||||
/**
|
||||
* TODO Add Description
|
||||
* Send multiple {@link TimeQueryRequest}s at once. This can be more efficient
|
||||
* than sending multiple requests individually because it reduces the network
|
||||
* overhead. The response will be a List<List<DataTime>> where the list contains
|
||||
* one entry for each request, in the same order as the requests.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jul 1, 2011 rjpeter Initial creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Jul0 1, 2011 rjpeter Initial creation
|
||||
* Dec 18, 2013 2579 bsteffen Class javadoc
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rjpeter
|
||||
* @version 1.0
|
||||
* @see TimeQueryRequest
|
||||
*/
|
||||
@DynamicSerialize
|
||||
public class TimeQueryRequestSet implements IServerRequest {
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.raytheon.uf.common.serialization.ISerializableObject;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
|
||||
|
@ -37,9 +36,10 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
|||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 21, 2010 mschenke Initial creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Jan 21, 2010 mschenke Initial creation
|
||||
* Dec 18, 2013 2579 bsteffen Remove ISerializableObject
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -47,7 +47,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
|||
* @version 1.0
|
||||
*/
|
||||
@DynamicSerialize
|
||||
public class DbQueryResponse implements ISerializableObject {
|
||||
public class DbQueryResponse {
|
||||
|
||||
public static final String ENTITY_RESULT_KEY = null;
|
||||
|
||||
|
|
|
@ -19,28 +19,32 @@
|
|||
**/
|
||||
package com.raytheon.uf.common.dataquery.responses;
|
||||
|
||||
import com.raytheon.uf.common.serialization.ISerializableObject;
|
||||
import com.raytheon.uf.common.dataquery.requests.DbQueryRequestSet;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
|
||||
/**
|
||||
* TODO Add Description
|
||||
* Response to a {@link DbQueryResponseSet}, contains a response to every
|
||||
* request in the same order.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jul 1, 2011 rjpeter Initial creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Jul 01, 2011 rjpeter Initial creation
|
||||
* Dec 18, 2013 2579 bsteffen Remove ISerializableObject
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rjpeter
|
||||
* @version 1.0
|
||||
* @see DbQueryResponse
|
||||
* @see DbQueryRequestSet
|
||||
*/
|
||||
@DynamicSerialize
|
||||
public class DbQueryResponseSet implements ISerializableObject {
|
||||
public class DbQueryResponseSet {
|
||||
@DynamicSerializeElement
|
||||
private DbQueryResponse[] results;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue