Author: [log in to unmask]
Date: Tue Dec 1 15:42:26 2015
New Revision: 3997
Log:
Rewrite tag command so run range overlaps are handled correctly by using a disambiguation action (last created by default).
Modified:
java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java
java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java
Modified: java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java
=============================================================================
--- java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java (original)
+++ java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/api/ConditionsRecord.java Tue Dec 1 15:42:26 2015
@@ -8,6 +8,7 @@
import org.hps.conditions.database.ConditionsRecordConverter;
import org.hps.conditions.database.Converter;
import org.hps.conditions.database.Field;
+import org.hps.conditions.database.MultipleCollectionsAction;
import org.hps.conditions.database.Table;
/**
@@ -233,6 +234,33 @@
public final ConditionsRecordCollection sortedByUpdated() {
return (ConditionsRecordCollection) this.sorted(new UpdatedComparator());
}
+
+ /**
+ * Find a unique record using the selected action for disambiguating conditions with the same key.
+ * @param key the name of the key
+ * @param action the disambiguation action
+ * @return the unique conditions record or <code>null</code> if does not exist
+ */
+ public ConditionsRecord findUniqueRecord(String key, MultipleCollectionsAction action) {
+ ConditionsRecord record = null;
+ ConditionsRecordCollection keyRecords = this.findByKey(key);
+ if (keyRecords.size() > 0) {
+ if (keyRecords.size() == 1) {
+ record = keyRecords.get(0);
+ } else {
+ if (action.equals(MultipleCollectionsAction.LAST_UPDATED)) {
+ record = sortedByUpdated().get(this.size() - 1);
+ } else if (action.equals(MultipleCollectionsAction.LAST_CREATED)) {
+ record = sortedByCreated().get(this.size() - 1);
+ } else if (action.equals(MultipleCollectionsAction.LATEST_RUN_START)) {
+ record = sortedByRunStart().get(this.size() - 1);
+ } else if (action.equals(MultipleCollectionsAction.ERROR)) {
+ throw new RuntimeException("Multiple ConditionsRecord object found for conditions key " + key + ".");
+ }
+ }
+ }
+ return record;
+ }
}
/**
Modified: java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java
=============================================================================
--- java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java (original)
+++ java/branches/jeremy-dev/conditions/src/main/java/org/hps/conditions/cli/TagCommand.java Tue Dec 1 15:42:26 2015
@@ -1,10 +1,9 @@
package org.hps.conditions.cli;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
import java.sql.SQLException;
-import java.util.logging.Level;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
import java.util.logging.Logger;
import org.apache.commons.cli.CommandLine;
@@ -16,17 +15,16 @@
import org.hps.conditions.api.ConditionsTag;
import org.hps.conditions.api.ConditionsTag.ConditionsTagCollection;
import org.hps.conditions.api.DatabaseObjectException;
-import org.hps.conditions.api.TableMetaData;
import org.hps.conditions.api.TableRegistry;
+import org.hps.conditions.database.DatabaseConditionsManager;
import org.hps.conditions.database.MultipleCollectionsAction;
+import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
/**
* Create a conditions system tag.
* <p>
* The tag groups together conditions records from the <i>conditions</i> database table with a run validity range that
* is between a specified starting and ending run.
- * <p>
- * Tagging will not disambiguate overlapping conditions, which is done at run-time based on the current run number.
*
* @author Jeremy McCormick, SLAC
*/
@@ -41,20 +39,29 @@
* Defines command options.
*/
private static Options OPTIONS = new Options();
+
+ private MultipleCollectionsAction multipleCollectionsAction = MultipleCollectionsAction.LAST_CREATED;
+
+ private static String getMultipleCollectionsActionString() {
+ StringBuffer sb = new StringBuffer();
+ for (MultipleCollectionsAction action : MultipleCollectionsAction.values()) {
+ sb.append(action.name() + " ");
+ }
+ sb.setLength(sb.length() - 1);
+ return sb.toString();
+ }
/**
* Define all command options.
*/
static {
- OPTIONS.addOption(new Option("h", false, "Show help for tag command"));
- OPTIONS.addOption(new Option("t", true, "Conditions tag name"));
- OPTIONS.addOption(new Option("s", true, "Starting run number (required)"));
- OPTIONS.getOption("s").setRequired(true);
- OPTIONS.addOption(new Option("e", true, "Ending run number (default is unlimited)"));
- OPTIONS.getOption("t").setRequired(true);
- OPTIONS.addOption(new Option("m", true,
- "MultipleCollectionsAction to use for disambiguation (default is LAST_CREATED)"));
- OPTIONS.addOption(new Option("d", false, "Don't prompt before making tag (be careful!)"));
+ OPTIONS.addOption(new Option("h", "help", false, "Show help for tag command"));
+ OPTIONS.addOption(new Option("t", "tag", true, "Conditions tag name"));
+ OPTIONS.addOption(new Option("s", "run-start", true, "Starting run number (required)"));
+ OPTIONS.addOption(new Option("e", "run-end", true, "Ending run number (required)"));
+ OPTIONS.addOption(new Option("m", "multiple", true,
+ "set run overlap handling (" + getMultipleCollectionsActionString() + ")"));
+ OPTIONS.addOption(new Option("d", false, "Don't prompt before making tag (careful!)"));
}
/**
@@ -103,6 +110,11 @@
} else {
throw new RuntimeException("Missing required -t argument with the tag name.");
}
+
+ // Check if tag exists already.
+ if (getManager().getAvailableTags().contains(tagName)) {
+ throw new RuntimeException("The tag '" + tagName + "' already exists in the database.");
+ }
// Starting run number (required).
int runStart = -1;
@@ -110,19 +122,16 @@
runStart = Integer.parseInt(commandLine.getOptionValue("s"));
LOGGER.config("run start set to " + runStart);
} else {
- throw new RuntimeException("missing require -s argument with starting run number");
- }
-
- // Ending run number (max integer is default).
- int runEnd = Integer.MAX_VALUE;
+ throw new RuntimeException("Missing required -s argument with starting run number.");
+ }
+
+ // Ending run number (required).
+ int runEnd = -1;
if (commandLine.hasOption("e")) {
runEnd = Integer.parseInt(commandLine.getOptionValue("e"));
LOGGER.config("run end set to " + runEnd);
- }
-
- // Run end must be greater than or equal to run start.
- if (runEnd < runStart) {
- throw new IllegalArgumentException("runEnd < runStart");
+ } else {
+ throw new RuntimeException("Missing required -e argument with starting run number.");
}
// Action for disambiguating overlapping collections (default is to use the most recent creation date).
@@ -131,20 +140,24 @@
multipleCollectionsAction = MultipleCollectionsAction
.valueOf(commandLine.getOptionValue("m").toUpperCase());
}
- LOGGER.config("multiple collections action set tco " + multipleCollectionsAction);
+ LOGGER.config("run overlaps will be disambiguated using " + multipleCollectionsAction);
// Whether to prompt before tagging (default is yes).
boolean promptBeforeTagging = true;
if (commandLine.hasOption("d")) {
promptBeforeTagging = false;
}
- LOGGER.config("prompt before tagging: " + promptBeforeTagging);
+ LOGGER.config("prompt before tagging = " + promptBeforeTagging);
// Conditions system configuration.
this.getManager().setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
// Find all the applicable conditions records by their run number ranges.
ConditionsRecordCollection tagConditionsRecordCollection = this.findConditionsRecords(runStart, runEnd);
+
+ if (tagConditionsRecordCollection.size() == 0) {
+ throw new RuntimeException("No records found for tag.");
+ }
LOGGER.info("found " + tagConditionsRecordCollection.size() + " conditions records for the tag");
@@ -152,8 +165,8 @@
final ConditionsTagCollection conditionsTagCollection = this.createConditionsTagCollection(
tagConditionsRecordCollection, tagName);
- LOGGER.info("created " + conditionsTagCollection.size() + " tag records ..." + '\n' + conditionsTagCollection);
-
+ printConditionsRecords(tagConditionsRecordCollection);
+
// Prompt user to verify tag creation.
boolean createTag = true;
if (promptBeforeTagging) {
@@ -178,68 +191,85 @@
LOGGER.info("done!");
}
-
- /**
- * Find all the conditions records that are applicable for the given run range.
- * <p>
- * Overlapping run numbers in conditions with the same key are not disambiguated.
- * This must be done in the user's job at runtime; usually the most recently created
- * conditions record will be used if multiple one's are applicable to the current run.
- *
- * @param runStart the start run
- * @param runEnd the end run (must be greater than or equal to <code>runStart</code>)
- * @return the conditions records that fall in the run range
+
+ /**
+ * Print information about conditions records in the tag to the log.
+ *
+ * @param collection the conditions tag collection
+ */
+ private void printConditionsRecords(ConditionsRecordCollection records) {
+ StringBuffer sb = new StringBuffer();
+ Set<String> keys = new TreeSet<String>(records.getConditionsKeys());
+ for (String key : keys) {
+ ConditionsRecordCollection keyRecords = records.findByKey(key);
+ keyRecords.sortByKey();
+ for (ConditionsRecord record : keyRecords) {
+ sb.append("conditions_id: " + record.getRowId() + ", name: " + record.getName() + ", collection_id: "
+ + record.getCollectionId() + ", run_start: " + record.getRunStart()
+ + ", run_end: " + record.getRunEnd() + ", notes: " + record.getNotes() + '\n');
+
+ }
+ }
+ LOGGER.info("including " + records.size() + " records in tag ..." + '\n' + sb.toString());
+ }
+
+ /**
+ * Scan through a run range to find conditions records for the tag.
+ *
+ * @param runStart the starting run number
+ * @param runEnd the ending run number
+ * @return the conditions records for the tag
*/
private ConditionsRecordCollection findConditionsRecords(final int runStart, final int runEnd) {
- if (runStart > runEnd) {
- throw new IllegalArgumentException("runStart > runEnd");
- }
- if (runStart < 0) {
- throw new IllegalArgumentException("invalid runStart: " + runStart);
- }
- if (runEnd < 0) {
- throw new IllegalArgumentException("invalid runEnd: " + runEnd);
- }
- final Connection connection = this.getManager().getConnection();
- final ConditionsRecordCollection conditionsRecordCollection = new ConditionsRecordCollection();
- final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName("conditions");
- PreparedStatement statement = null;
- try {
- /*
- * SQL statement handles 3 cases:
- * 1) condition's run_start in range
- * 2) condition's run_end in range
- * 3) condition's run_start and run_end enclose the range
- */
- statement = connection
- .prepareStatement("SELECT id FROM conditions WHERE (run_start >= ? and run_start <= ?) or (run_end >= ? and run_end <= ?)"
- + " or (run_start <= ? and run_end >= ?)");
- statement.setInt(1, runStart);
- statement.setInt(2, runEnd);
- statement.setInt(3, runStart);
- statement.setInt(4, runEnd);
- statement.setInt(5, runStart);
- statement.setInt(6, runEnd);
-
- final ResultSet resultSet = statement.executeQuery();
- while (resultSet.next()) {
- final ConditionsRecord record = new ConditionsRecord();
- record.setConnection(connection);
- record.setTableMetaData(tableMetaData);
- record.select(resultSet.getInt(1));
- conditionsRecordCollection.add(record);
- }
- } catch (DatabaseObjectException | ConditionsObjectException | SQLException e) {
- throw new RuntimeException(e);
- } finally {
+ if (runStart < 0 ) {
+ throw new IllegalArgumentException("The run start " + runStart + " is invalid.");
+ }
+ if (runEnd < 0 ) {
+ throw new IllegalArgumentException("The run end " + runEnd + " is invalid.");
+ }
+ if (runStart > runEnd ) {
+ throw new IllegalArgumentException("The run start is greater than the run end.");
+ }
+ DatabaseConditionsManager dbManager = this.getManager();
+ if (dbManager.isFrozen()) {
+ dbManager.unfreeze();
+ }
+ if (!dbManager.getActiveTags().isEmpty()) {
+ dbManager.clearTags();
+ }
+ final String detectorName = "HPS-dummy-detector";
+ ConditionsRecordCollection tagRecords = new ConditionsRecordCollection();
+ Set<Integer> ids = new HashSet<Integer>();
+ for (int run = runStart; run <= runEnd; run++) {
+ LOGGER.info("loading run " + run);
try {
- if (statement != null) {
- statement.close();
+ dbManager.setDetector(detectorName, run);
+ } catch (ConditionsNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ ConditionsRecordCollection runRecords = dbManager.getConditionsRecords();
+ Set<String> keys = runRecords.getConditionsKeys();
+ LOGGER.fine("run has " + runRecords.size() + " conditions records");
+ for (String key : keys) {
+ ConditionsRecord record = runRecords.findUniqueRecord(key, this.multipleCollectionsAction);
+ if (record == null) {
+ throw new RuntimeException("Missing expected unique condition record for " + key + ".");
}
- } catch (final SQLException e) {
- e.printStackTrace();
- }
- }
- return conditionsRecordCollection;
+ if (!ids.contains(record.getRowId())) {
+ try {
+ LOGGER.fine("adding conditions to tag ..." + '\n' + record.toString());
+ tagRecords.add(record);
+ ids.add(record.getRowId());
+ } catch (ConditionsObjectException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ LOGGER.fine("Conditions record with row id " + record.getRowId() + " is already in the tag.");
+ }
+ }
+ LOGGER.info("done processing run " + run);
+ }
+ LOGGER.info("Found " + tagRecords.size() + " conditions records for tag.");
+ return tagRecords;
}
}
|