diff --git a/src/main/java/com/microsoft/dhalion/core/Action.java b/src/main/java/com/microsoft/dhalion/core/Action.java index eea46fa..e376c16 100644 --- a/src/main/java/com/microsoft/dhalion/core/Action.java +++ b/src/main/java/com/microsoft/dhalion/core/Action.java @@ -9,47 +9,27 @@ package com.microsoft.dhalion.core; import com.microsoft.dhalion.api.IResolver; import java.time.Instant; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; /** * {@link Action} is a representation of a action taken by {@link IResolver} to improve system health. */ -public class Action { - // action type - private final String type; - - // instant when this action was created - private final Instant instant; - - // Diagnosis relevant to this action - private final Collection diagnosis; - - public Action(String type, Instant instant, Collection diagnosis) { - this.type = type; - this.instant = instant; - this.diagnosis = new ArrayList<>(diagnosis); +public class Action extends Outcome { + public Action(String type, Instant instant, Collection assignments) { + super(type, instant, assignments); } - public String getType() { - return type; - } - - public Instant getInstant() { - return instant; - } - - public Collection getDiagnosis() { - return Collections.unmodifiableCollection(diagnosis); + public Action(int id, String symptomType, Instant instant, Collection assignments) { + super(id, symptomType, instant, assignments); } @Override public String toString() { return "Action{" + - "type='" + type + '\'' + - ", instant=" + instant + - ", diagnosis=" + diagnosis + + "id=" + id() + + ", type=" + type() + + ", instant=" + instant() + + ", assignments=" + assignments() + '}'; } } diff --git a/src/main/java/com/microsoft/dhalion/core/ActionArray.java b/src/main/java/com/microsoft/dhalion/core/ActionArray.java new file mode 100644 index 0000000..c0345e8 --- /dev/null +++ b/src/main/java/com/microsoft/dhalion/core/ActionArray.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * This program is made available under the terms of the MIT License. + * See the LICENSE file in the project root for more information. + */ +package com.microsoft.dhalion.core; + +import tech.tablesaw.api.Table; + +import java.time.Instant; +import java.util.Collection; +import java.util.Collections; + +//TODO thread safety + +/** + * An ordered collection of {@link Action}s. It provides methods to filter, query and aggregate the + * {@link Action}s. + */ +public class ActionArray extends OutcomeArray { + private ActionArray() { + super("Actions"); + } + + private ActionArray(Table table) { + super(table); + } + + /** + * @param actions collections of actions + * @return a {@link ActionArray} holding the input + */ + public ActionArray of(Collection actions) { + ActionArray array = new ActionArray(); + array.addAll(actions); + return array; + } + + private void addAll(Collection actions) { + actions.forEach(action -> { + action.assignments().forEach(assignment -> { + id.append(action.id()); + this.assignment.append(assignment); + type.append(action.type()); + timeStamp.append(action.instant().toEpochMilli()); + }); + }); + } + + /** + * @param id unique action id + * @return {@link Action}s with the given id + */ + public ActionArray id(int id) { + Table result = filterId(id); + return new ActionArray(result); + } + + /** + * Retains all {@link Action}s with given action type + * + * @param types names of the action types, not null + * @return {@link ActionArray} containing filtered {@link Action}s + */ + public ActionArray type(Collection types) { + return new ActionArray(filterType(types)); + } + + /** + * @param type a action type + * @return {@link ActionArray} containing filtered {@link Action}s + * @see #type(Collection) + */ + public ActionArray type(String type) { + return type(Collections.singletonList(type)); + } + + /** + * Retains all {@link Action}s with given assignment ids. + * + * @param assignments assignment ids, not null + * @return {@link ActionArray} containing filtered {@link Action}s + */ + public ActionArray assignment(Collection assignments) { + return new ActionArray(filterAssignment(assignments)); + } + + /** + * @param assignment assignment id + * @return {@link ActionArray} containing filtered {@link Action}s + * @see #assignment(Collection) + */ + public ActionArray assignment(String assignment) { + return assignment(Collections.singletonList(assignment)); + } + + /** + * Retains all {@link Action}s with timestamp in the given range. + * + * @param oldest the oldest timestamp, null to ignore this condition + * @param newest the newest timestamp, null to ignore this condition + * @return {@link ActionArray} containing filtered {@link Action}s + */ + public ActionArray between(Instant oldest, Instant newest) { + return new ActionArray(filterTime(oldest, newest)); + } + + /** + * Sorts the {@link Action}s in this collection in the order of the specified keys + * + * @param descending false for ascending order, true for descending + * @param sortKeys one or more sort keys, e.g. {@link SortKey#ID} + * @return ordered {@link Action}s + */ + public ActionArray sort(boolean descending, SortKey... sortKeys) { + return new ActionArray(sortTable(descending, sortKeys)); + } + + /** + * Retains the {@link Action} positioned between first and last, both inclusive, + * positions in this collection + * + * @param first the lowest index {@link Action} to be retained + * @param last the highest index {@link Action} to be retained + * @return {@link ActionArray} containing specific {@link Action}s + */ + public ActionArray slice(int first, int last) { + return new ActionArray(sliceTable(first, last)); + } + + Action row2Obj(int index) { + return new Action(id.get(index), + type.get(index), + Instant.ofEpochMilli(timeStamp.get(index)), + Collections.singletonList(assignment.get(index))); + } + + + /** + * Builds {@link ActionArray} instance and provides ability to update it. + */ + public static class Builder { + private final ActionArray actionsArray = new ActionArray(); + + public ActionArray get() { + return actionsArray; + } + + public void addAll(Collection actions) { + if (actions == null) { + return; + } + + this.actionsArray.addAll(actions); + } + } +} diff --git a/src/main/java/com/microsoft/dhalion/core/Diagnosis.java b/src/main/java/com/microsoft/dhalion/core/Diagnosis.java index 7c4a7f6..d8e84b6 100644 --- a/src/main/java/com/microsoft/dhalion/core/Diagnosis.java +++ b/src/main/java/com/microsoft/dhalion/core/Diagnosis.java @@ -7,48 +7,28 @@ package com.microsoft.dhalion.core; import java.time.Instant; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; /** * A {@link Diagnosis} is a representation of a possible causes of one or more {@link Symptom}s. For e.g. resource * under-provisioning */ -public class Diagnosis { - // diagnosis identifier - private final String type; - - // instant when this diagnosis was created - private final Instant instant; - - // symptoms corresponding to this symptom - private final Collection symptoms; - - public Diagnosis(String type, Instant instant, Collection symptoms) { - this.type = type; - this.instant = instant; - this.symptoms = new ArrayList<>(symptoms); +public class Diagnosis extends Outcome { + public Diagnosis(String type, Instant instant, Collection assignments) { + super(type, instant, assignments); } - public String getType() { - return type; - } - - public Instant getInstant() { - return instant; - } - - public Collection getSymptoms() { - return Collections.unmodifiableCollection(symptoms); + public Diagnosis(int id, String symptomType, Instant instant, Collection assignments) { + super(id, symptomType, instant, assignments); } @Override public String toString() { return "Diagnosis{" + - "type='" + type + '\'' + - ", instant=" + instant + - ", symptoms=" + symptoms + + "id=" + id() + + ", type=" + type() + + ", instant=" + instant() + + ", assignments=" + assignments() + '}'; } } diff --git a/src/main/java/com/microsoft/dhalion/core/DiagnosisArray.java b/src/main/java/com/microsoft/dhalion/core/DiagnosisArray.java new file mode 100644 index 0000000..fb1c451 --- /dev/null +++ b/src/main/java/com/microsoft/dhalion/core/DiagnosisArray.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * This program is made available under the terms of the MIT License. + * See the LICENSE file in the project root for more information. + */ +package com.microsoft.dhalion.core; + +import tech.tablesaw.api.Table; + +import java.time.Instant; +import java.util.Collection; +import java.util.Collections; + +//TODO thread safety + +/** + * An ordered collection of {@link Diagnosis}. It provides methods to filter, query and aggregate the + * {@link Diagnosis} . + */ +public class DiagnosisArray extends OutcomeArray { + private DiagnosisArray() { + super("Symptoms"); + } + + private DiagnosisArray(Table table) { + super(table); + } + + /** + * @param diagnosis collections of diagnosis + * @return a {@link DiagnosisArray} holding the input + */ + public DiagnosisArray of(Collection diagnosis) { + DiagnosisArray array = new DiagnosisArray(); + array.addAll(diagnosis); + return array; + } + + private void addAll(Collection diagnosis) { + diagnosis.forEach(diagnoses -> { + diagnoses.assignments().forEach(assignment -> { + id.append(diagnoses.id()); + this.assignment.append(assignment); + type.append(diagnoses.type()); + timeStamp.append(diagnoses.instant().toEpochMilli()); + }); + }); + } + + /** + * @param id unique diagnosis id + * @return {@link Diagnosis} with the given id + */ + public DiagnosisArray id(int id) { + Table result = filterId(id); + return new DiagnosisArray(result); + } + + /** + * Retains all {@link Diagnosis} with given diagnosis type + * + * @param types names of the diagnosis types, not null + * @return {@link DiagnosisArray} containing filtered {@link Diagnosis} + */ + public DiagnosisArray type(Collection types) { + return new DiagnosisArray(filterType(types)); + } + + /** + * @param type a diagnosis type + * @return {@link DiagnosisArray} containing filtered {@link Diagnosis} + * @see #type(Collection) + */ + public DiagnosisArray type(String type) { + return type(Collections.singletonList(type)); + } + + /** + * Retains all {@link Diagnosis} with given assignment ids. + * + * @param assignments assignment ids, not null + * @return {@link DiagnosisArray} containing filtered {@link Diagnosis} + */ + public DiagnosisArray assignment(Collection assignments) { + return new DiagnosisArray(filterAssignment(assignments)); + } + + /** + * @param assignment assignment id + * @return {@link DiagnosisArray} containing filtered {@link Diagnosis} + * @see #assignment(Collection) + */ + public DiagnosisArray assignment(String assignment) { + return assignment(Collections.singletonList(assignment)); + } + + /** + * Retains all {@link Diagnosis} with timestamp in the given range. + * + * @param oldest the oldest timestamp, null to ignore this condition + * @param newest the newest timestamp, null to ignore this condition + * @return {@link DiagnosisArray} containing filtered {@link Diagnosis} + */ + public DiagnosisArray between(Instant oldest, Instant newest) { + return new DiagnosisArray(filterTime(oldest, newest)); + } + + /** + * Sorts the {@link Diagnosis} in this collection in the order of the specified keys + * + * @param descending false for ascending order, true for descending + * @param sortKeys one or more sort keys, e.g. {@link SortKey#ID} + * @return ordered {@link Diagnosis} + */ + public DiagnosisArray sort(boolean descending, SortKey... sortKeys) { + return new DiagnosisArray(sortTable(descending, sortKeys)); + } + + /** + * Retains the {@link Diagnosis} positioned between first and last, both inclusive, + * positions in this collection + * + * @param first the lowest index {@link Diagnosis} to be retained + * @param last the highest index {@link Diagnosis} to be retained + * @return {@link DiagnosisArray} containing specific {@link Diagnosis}s + */ + public DiagnosisArray slice(int first, int last) { + return new DiagnosisArray(sliceTable(first, last)); + } + + Diagnosis row2Obj(int index) { + return new Diagnosis(id.get(index), + type.get(index), + Instant.ofEpochMilli(timeStamp.get(index)), + Collections.singletonList(assignment.get(index))); + } + + + /** + * Builds {@link DiagnosisArray} instance and provides ability to update it. + */ + public static class Builder { + private final DiagnosisArray diagnosisArray = new DiagnosisArray(); + + public DiagnosisArray get() { + return diagnosisArray; + } + + public void addAll(Collection diagnosis) { + if (diagnosis == null) { + return; + } + + this.diagnosisArray.addAll(diagnosis); + } + } +} diff --git a/src/main/java/com/microsoft/dhalion/core/MeasurementsArray.java b/src/main/java/com/microsoft/dhalion/core/MeasurementsArray.java index b26c723..65d8e36 100644 --- a/src/main/java/com/microsoft/dhalion/core/MeasurementsArray.java +++ b/src/main/java/com/microsoft/dhalion/core/MeasurementsArray.java @@ -84,6 +84,10 @@ public class MeasurementsArray { }); } + /** + * @param measurements collections of measurements + * @return a {@link MeasurementsArray} holding the input + */ public MeasurementsArray of(Collection measurements) { MeasurementsArray array = new MeasurementsArray(); array.addAll(measurements); diff --git a/src/main/java/com/microsoft/dhalion/core/Outcome.java b/src/main/java/com/microsoft/dhalion/core/Outcome.java new file mode 100644 index 0000000..a052a21 --- /dev/null +++ b/src/main/java/com/microsoft/dhalion/core/Outcome.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * This program is made available under the terms of the MIT License. + * See the LICENSE file in the project root for more information. + */ +package com.microsoft.dhalion.core; + +import com.microsoft.dhalion.api.IDetector; + +import java.time.Instant; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A {@link Outcome} represent result of execution of a Dhalion phase. For e.g. {@link IDetector} phase's results in + * {@link Symptom}s + */ +abstract class Outcome { + private static final AtomicInteger idGenerator = new AtomicInteger(1); + + // unique identifier of this instance + private final int id; + + // outcome category identifier + private final String type; + + // instant when this outcome was created + private final Instant instant; + + // ids of objects to which this outcome can be attributed to, for e.g. slow instance's id + private final Collection assignments; + + Outcome(String type, Instant instant, Collection assignments) { + this(idGenerator.incrementAndGet(), type, instant, assignments); + } + + Outcome(int id, String type, Instant instant, Collection assignments) { + this.id = id; + this.type = type; + this.instant = instant; + this.assignments = Collections.unmodifiableCollection(assignments); + } + + public int id() { + return id; + } + + public String type() { + return type; + } + + public Instant instant() { + return instant; + } + + public Collection assignments() { + return assignments; + } +} + diff --git a/src/main/java/com/microsoft/dhalion/core/OutcomeArray.java b/src/main/java/com/microsoft/dhalion/core/OutcomeArray.java new file mode 100644 index 0000000..6663859 --- /dev/null +++ b/src/main/java/com/microsoft/dhalion/core/OutcomeArray.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * This program is made available under the terms of the MIT License. + * See the LICENSE file in the project root for more information. + */ +package com.microsoft.dhalion.core; + +import tech.tablesaw.api.CategoryColumn; +import tech.tablesaw.api.IntColumn; +import tech.tablesaw.api.LongColumn; +import tech.tablesaw.api.Table; +import tech.tablesaw.columns.ColumnReference; +import tech.tablesaw.filtering.Filter; +import tech.tablesaw.filtering.LongGreaterThanOrEqualTo; +import tech.tablesaw.filtering.LongLessThanOrEqualTo; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static tech.tablesaw.api.QueryHelper.both; +import static tech.tablesaw.api.QueryHelper.column; +import static tech.tablesaw.api.QueryHelper.or; + +//TODO thread safety + +/** + * An ordered collection of {@link Outcome} instances. This class provides methods to filter, query and aggregate the + * {@link Outcome} instances. + */ +public abstract class OutcomeArray { + final Table table; + final CategoryColumn type; + final IntColumn id; + final CategoryColumn assignment; + final LongColumn timeStamp; + + private static final String ID = SortKey.ID.name(); + private static final String ASSIGNMENT = SortKey.ASSIGNMENT.name(); + private static final String TIME_STAMP = SortKey.TIME_STAMP.name(); + private static final String TYPE = SortKey.TYPE.name(); + + public enum SortKey { + ID, ASSIGNMENT, TIME_STAMP, TYPE + } + + OutcomeArray(String name) { + id = new IntColumn(ID); + assignment = new CategoryColumn(ASSIGNMENT); + type = new CategoryColumn(TYPE); + timeStamp = new LongColumn(TIME_STAMP); + + table = Table.create(name); + table.addColumn(id); + table.addColumn(assignment); + table.addColumn(type); + table.addColumn(timeStamp); + } + + OutcomeArray(Table table) { + this.table = table; + id = this.table.intColumn(ID); + assignment = this.table.categoryColumn(ASSIGNMENT); + type = this.table.categoryColumn(TYPE); + timeStamp = this.table.longColumn(TIME_STAMP); + } + + Table filterId(int id) { + return table.selectWhere(column(ID).isEqualTo(id)); + } + + Table filterType(Collection types) { + return applyCategoryFilter(types, TYPE); + } + + Table filterType(String type) { + return filterType(Collections.singletonList(type)); + } + + Table filterAssignment(Collection assignments) { + return applyCategoryFilter(assignments, ASSIGNMENT); + } + + Table filterAssignment(String assignment) { + return filterAssignment(Collections.singletonList(assignment)); + } + + private Table applyCategoryFilter(Collection names, String column) { + List filters = names.stream().map(name -> column(column).isEqualTo(name)).collect(Collectors.toList()); + return table.selectWhere(or(filters)); + } + + Table filterTime(Instant oldest, Instant newest) { + return table.selectWhere( + both(new LongGreaterThanOrEqualTo(new ColumnReference(TIME_STAMP), oldest.toEpochMilli()), + new LongLessThanOrEqualTo(new ColumnReference(TIME_STAMP), newest.toEpochMilli()))); + } + + /** + * @return count of {@link Outcome} rows in this collection + */ + public int size() { + return table.rowCount(); + } + + /** + * @return unique ids in this collection + */ + public Collection uniqueIds() { + ArrayList result = new ArrayList<>(); + IntColumn uniqueColumn = id.unique(); + for (int id : uniqueColumn) { + result.add(id); + } + return result; + } + + /** + * @return unique {@link Outcome} types in this collection + */ + public Collection uniqueTypes() { + ArrayList result = new ArrayList<>(); + CategoryColumn uniqueColumn = type.unique(); + uniqueColumn.forEach(result::add); + return result; + } + + /** + * @return unique {@link Instant}s at which {@link Outcome} objects were created + */ + public Collection uniqueInstants() { + ArrayList result = new ArrayList<>(); + LongColumn uniqueColumn = timeStamp.unique(); + for (Long ts : uniqueColumn) { + result.add(Instant.ofEpochMilli(ts)); + } + return result; + } + + Table sortTable(boolean descending, SortKey... sortKeys) { + String[] columns = new String[sortKeys.length]; + for (int i = 0; i < sortKeys.length; i++) { + columns[i] = sortKeys[i].name(); + } + + Table result; + if (descending) { + result = table.sortDescendingOn(columns); + } else { + result = table.sortAscendingOn(columns); + } + return result; + } + + Table sliceTable(int first, int last) { + return table.selectRows(first, last); + } + + /** + * @return the first {@link Outcome} in this collection, if present + */ + public T first() { + return get(0); + } + + /** + * @return the last {@link Outcome} in this collection, if present + */ + public T last() { + return get(table.rowCount() - 1); + } + + /** + * @return all {@link Outcome} objects in this collection + */ + public Collection get() { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < table.rowCount(); i++) { + result.add(row2Obj(i)); + } + return result; + } + + /** + * @param index position in the table + * @return {@link Outcome} at the requested position + */ + public T get(int index) { + if (index < 0 || index >= table.rowCount() || table.isEmpty()) { + return null; + } + + return row2Obj(index); + } + + abstract T row2Obj(int index); + + public String toStringForDebugging() { + return table.print(table.rowCount()); + } +} diff --git a/src/main/java/com/microsoft/dhalion/core/Symptom.java b/src/main/java/com/microsoft/dhalion/core/Symptom.java index b02c193..130f877 100644 --- a/src/main/java/com/microsoft/dhalion/core/Symptom.java +++ b/src/main/java/com/microsoft/dhalion/core/Symptom.java @@ -7,63 +7,28 @@ package com.microsoft.dhalion.core; import java.time.Instant; -import java.util.ArrayList; import java.util.Collection; -import java.util.concurrent.atomic.AtomicInteger; /** * A {@link Symptom} identifies an anomaly or a potential health issue in a specific component of a * distributed application. For e.g. identification of irregular processing latency. */ -public class Symptom { - private static final AtomicInteger idGenerator = new AtomicInteger(1); - - // symptom identifier - private final String type; - - // unique identifier of this instance - private final int id; - - // instant when this symptom was created - private final Instant instant; - - // ids to which the symptom is assigned, for e.g. instances - private final Collection assignments; - +public class Symptom extends Outcome { public Symptom(String symptomType, Instant instant, Collection assignments) { - this(idGenerator.incrementAndGet(), symptomType, instant, assignments); + super(symptomType, instant, assignments); } public Symptom(int id, String symptomType, Instant instant, Collection assignments) { - this.id = id; - this.type = symptomType; - this.instant = instant; - this.assignments = new ArrayList<>(assignments); - } - - public int id() { - return id; - } - - public String type() { - return type; - } - - public Instant instant() { - return instant; - } - - public Collection assignments() { - return assignments; + super(id, symptomType, instant, assignments); } @Override public String toString() { return "Symptom{" + - "type=" + type + - ", id=" + id + - ", instant=" + instant + - ", assignments=" + assignments + + "type=" + type() + + ", id=" + id() + + ", instant=" + instant() + + ", assignments=" + assignments() + '}'; } } diff --git a/src/main/java/com/microsoft/dhalion/core/SymptomsArray.java b/src/main/java/com/microsoft/dhalion/core/SymptomsArray.java index 8eb86a8..a25e311 100644 --- a/src/main/java/com/microsoft/dhalion/core/SymptomsArray.java +++ b/src/main/java/com/microsoft/dhalion/core/SymptomsArray.java @@ -6,25 +6,11 @@ */ package com.microsoft.dhalion.core; -import tech.tablesaw.api.CategoryColumn; -import tech.tablesaw.api.IntColumn; -import tech.tablesaw.api.LongColumn; import tech.tablesaw.api.Table; -import tech.tablesaw.columns.ColumnReference; -import tech.tablesaw.filtering.Filter; -import tech.tablesaw.filtering.LongGreaterThanOrEqualTo; -import tech.tablesaw.filtering.LongLessThanOrEqualTo; import java.time.Instant; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import static tech.tablesaw.api.QueryHelper.both; -import static tech.tablesaw.api.QueryHelper.column; -import static tech.tablesaw.api.QueryHelper.or; //TODO thread safety @@ -32,41 +18,23 @@ import static tech.tablesaw.api.QueryHelper.or; * An ordered collection of {@link Symptom}s. It provides methods to filter, query and aggregate the * {@link Symptom}s. */ -public class SymptomsArray { - private final Table symptoms; - private CategoryColumn type; - private IntColumn id; - private CategoryColumn assignment; - private LongColumn timeStamp; - - public enum SortKey { - ID, ASSIGNMENT, TIME_STAMP, TYPE - } - - private static final String ID = SortKey.ID.name(); - private static final String ASSIGNMENT = SortKey.ASSIGNMENT.name(); - private static final String TIME_STAMP = SortKey.TIME_STAMP.name(); - private static final String TYPE = SortKey.TYPE.name(); - +public class SymptomsArray extends OutcomeArray { private SymptomsArray() { - id = new IntColumn(ID); - assignment = new CategoryColumn(ASSIGNMENT); - type = new CategoryColumn(TYPE); - timeStamp = new LongColumn(TIME_STAMP); - - symptoms = Table.create("Symptoms"); - symptoms.addColumn(id); - symptoms.addColumn(assignment); - symptoms.addColumn(type); - symptoms.addColumn(timeStamp); + super("Symptoms"); } private SymptomsArray(Table table) { - this.symptoms = table; - id = symptoms.intColumn(ID); - assignment = symptoms.categoryColumn(ASSIGNMENT); - type = symptoms.categoryColumn(TYPE); - timeStamp = symptoms.longColumn(TIME_STAMP); + super(table); + } + + /** + * @param symptoms collections of symptoms + * @return a {@link SymptomsArray} holding the input + */ + public SymptomsArray of(Collection symptoms) { + SymptomsArray array = new SymptomsArray(); + array.addAll(symptoms); + return array; } private void addAll(Collection symptoms) { @@ -85,7 +53,7 @@ public class SymptomsArray { * @return {@link Symptom}s with the given id */ public SymptomsArray id(int id) { - Table result = symptoms.selectWhere(column(ID).isEqualTo(id)); + Table result = filterId(id); return new SymptomsArray(result); } @@ -96,7 +64,7 @@ public class SymptomsArray { * @return {@link SymptomsArray} containing filtered {@link Symptom}s */ public SymptomsArray type(Collection types) { - return applyCategoryFilter(types, TYPE); + return new SymptomsArray(filterType(types)); } /** @@ -115,7 +83,7 @@ public class SymptomsArray { * @return {@link SymptomsArray} containing filtered {@link Symptom}s */ public SymptomsArray assignment(Collection assignments) { - return applyCategoryFilter(assignments, ASSIGNMENT); + return new SymptomsArray(filterAssignment(assignments)); } /** @@ -127,12 +95,6 @@ public class SymptomsArray { return assignment(Collections.singletonList(assignment)); } - private SymptomsArray applyCategoryFilter(Collection names, String column) { - List filters = names.stream().map(name -> column(column).isEqualTo(name)).collect(Collectors.toList()); - Table result = symptoms.selectWhere(or(filters)); - return new SymptomsArray(result); - } - /** * Retains all {@link Symptom}s with timestamp in the given range. * @@ -141,52 +103,7 @@ public class SymptomsArray { * @return {@link SymptomsArray} containing filtered {@link Symptom}s */ public SymptomsArray between(Instant oldest, Instant newest) { - Table result = symptoms.selectWhere( - both(new LongGreaterThanOrEqualTo(new ColumnReference(TIME_STAMP), oldest.toEpochMilli()), - new LongLessThanOrEqualTo(new ColumnReference(TIME_STAMP), newest.toEpochMilli()))); - - return new SymptomsArray(result); - } - - /** - * @return count of {@link Symptom}s in this collection - */ - public int size() { - return symptoms.rowCount(); - } - - /** - * @return unique symptom ids in this collection of {@link Symptom}s - */ - public Collection uniqueIds() { - ArrayList result = new ArrayList<>(); - IntColumn uniqueColumn = id.unique(); - for (int id : uniqueColumn) { - result.add(id); - } - return result; - } - - /** - * @return unique symptom types in this collection of {@link Symptom}s - */ - public Collection uniqueTypes() { - ArrayList result = new ArrayList<>(); - CategoryColumn uniqueColumn = type.unique(); - uniqueColumn.forEach(result::add); - return result; - } - - /** - * @return unique {@link Instant}s in this collection of {@link Symptom}s - */ - public Collection uniqueInstants() { - ArrayList result = new ArrayList<>(); - LongColumn uniqueColumn = timeStamp.unique(); - for (Long ts : uniqueColumn) { - result.add(Instant.ofEpochMilli(ts)); - } - return result; + return new SymptomsArray(filterTime(oldest, newest)); } /** @@ -197,18 +114,7 @@ public class SymptomsArray { * @return ordered {@link Symptom}s */ public SymptomsArray sort(boolean descending, SortKey... sortKeys) { - String[] columns = new String[sortKeys.length]; - for (int i = 0; i < sortKeys.length; i++) { - columns[i] = sortKeys[i].name(); - } - - Table result; - if (descending) { - result = symptoms.sortDescendingOn(columns); - } else { - result = symptoms.sortAscendingOn(columns); - } - return new SymptomsArray(result); + return new SymptomsArray(sortTable(descending, sortKeys)); } /** @@ -220,60 +126,10 @@ public class SymptomsArray { * @return {@link SymptomsArray} containing specific {@link Symptom}s */ public SymptomsArray slice(int first, int last) { - Table result = symptoms.selectRows(first, last); - return new SymptomsArray(result); + return new SymptomsArray(sliceTable(first, last)); } - /** - * @return the first {@link Symptom}, if present - */ - public Symptom first() { - if (symptoms.isEmpty()) { - return null; - } - - Table result = symptoms.first(1); - Collection measurementCollection = new SymptomsArray(result).get(); - return measurementCollection.iterator().next(); - } - - /** - * @return the last {@link Symptom}, if present - */ - public Symptom last() { - if (symptoms.isEmpty()) { - return null; - } - - Table result = symptoms.last(1); - Collection measurementCollection = new SymptomsArray(result).get(); - return measurementCollection.iterator().next(); - } - - /** - * @return all {@link Symptom}s in this collection - */ - public Collection get() { - ArrayList result = new ArrayList<>(); - for (int i = 0; i < symptoms.rowCount(); i++) { - result.add(row2Obj(i)); - } - return result; - } - - /** - * @param index position in the table - * @return {@link Symptom} at the requested position - */ - public Symptom get(int index) { - if (index < 0 || index >= symptoms.rowCount() || symptoms.isEmpty()) { - return null; - } - - return row2Obj(index); - } - - private Symptom row2Obj(int index) { + Symptom row2Obj(int index) { return new Symptom(id.get(index), type.get(index), Instant.ofEpochMilli(timeStamp.get(index)), @@ -281,10 +137,6 @@ public class SymptomsArray { } - public String toStringForDebugging() { - return symptoms.print(symptoms.rowCount()); - } - /** * Builds {@link SymptomsArray} instance and provides ability to update it. */ diff --git a/src/main/java/com/microsoft/dhalion/policy/PoliciesExecutor.java b/src/main/java/com/microsoft/dhalion/policy/PoliciesExecutor.java index d6c7798..872f30f 100644 --- a/src/main/java/com/microsoft/dhalion/policy/PoliciesExecutor.java +++ b/src/main/java/com/microsoft/dhalion/policy/PoliciesExecutor.java @@ -9,7 +9,9 @@ package com.microsoft.dhalion.policy; import com.microsoft.dhalion.api.IHealthPolicy; import com.microsoft.dhalion.core.Action; +import com.microsoft.dhalion.core.ActionArray; import com.microsoft.dhalion.core.Diagnosis; +import com.microsoft.dhalion.core.DiagnosisArray; import com.microsoft.dhalion.core.Measurement; import com.microsoft.dhalion.core.MeasurementsArray; import com.microsoft.dhalion.core.Symptom; @@ -70,8 +72,14 @@ public class PoliciesExecutor { policyContextMap.get(policy).measurementsArrayBuilder.addAll(measurements); Collection symptoms = policy.executeDetectors(measurements); + policyContextMap.get(policy).symptomsArrayBuilder.addAll(symptoms); + Collection diagnosis = policy.executeDiagnosers(symptoms); + policyContextMap.get(policy).diagnsisArrayBuilder.addAll(diagnosis); + Collection actions = policy.executeResolvers(diagnosis); + policyContextMap.get(policy).actionArrayBuilder.addAll(actions); + // TODO pretty print LOG.info(actions.toString()); @@ -91,17 +99,30 @@ public class PoliciesExecutor { public static class ExecutionContext { private final MeasurementsArray.Builder measurementsArrayBuilder; private final SymptomsArray.Builder symptomsArrayBuilder; + private final DiagnosisArray.Builder diagnsisArrayBuilder; + private final ActionArray.Builder actionArrayBuilder; private ExecutionContext() { measurementsArrayBuilder = new MeasurementsArray.Builder(); symptomsArrayBuilder = new SymptomsArray.Builder(); + diagnsisArrayBuilder = new DiagnosisArray.Builder(); + actionArrayBuilder = new ActionArray.Builder(); } public MeasurementsArray measurements() { return measurementsArrayBuilder.get(); } + public SymptomsArray symptoms() { return symptomsArrayBuilder.get(); } + + public DiagnosisArray diagnosis() { + return diagnsisArrayBuilder.get(); + } + + public ActionArray actions() { + return actionArrayBuilder.get(); + } } } diff --git a/src/test/java/com/microsoft/dhalion/core/SymptomsArrayTest.java b/src/test/java/com/microsoft/dhalion/core/SymptomsArrayTest.java index 822b994..33408c5 100644 --- a/src/test/java/com/microsoft/dhalion/core/SymptomsArrayTest.java +++ b/src/test/java/com/microsoft/dhalion/core/SymptomsArrayTest.java @@ -7,8 +7,8 @@ package com.microsoft.dhalion.core; +import com.microsoft.dhalion.core.OutcomeArray.SortKey; import com.microsoft.dhalion.core.SymptomsArray.Builder; -import com.microsoft.dhalion.core.SymptomsArray.SortKey; import org.junit.Before; import org.junit.Test;