/** * Checks that an experiment has a state "draft" and throws an exception * if it doesn't * * @param experiment Experiment object containing experiment metadata */ public void ensureStateIsDraft(Experiment experiment) { Experiment.State state = experiment.getState(); if (!state.equals(Experiment.State.DRAFT)) { throw new InvalidExperimentStateException(experiment.getID(), Experiment.State.DRAFT, experiment.getState()); } }
.append(startTime, other.getStartTime()) .append(endTime, other.getEndTime()) .append(state, other.getState()) .append(label, other.getLabel()) .append(applicationName, other.getApplicationName())
public void validateExperiment(Experiment experiment) { Experiment.State state = experiment.getState(); if (state.equals(Experiment.State.DELETED) || state.equals(Experiment.State.TERMINATED)) { return; } validateLabel(experiment.getLabel()); validateExperimentStartEnd(experiment.getStartTime(), experiment.getEndTime()); validateSamplingPercent(experiment.getSamplingPercent()); validateExperimentRule(experiment.getRule()); validateModelNameNotNullForPersonalizedExperiments(experiment.getIsPersonalizationEnabled() , experiment.getModelName()); }
/** * Checks that an experiment has a state "draft" and throws an exception * if it doesn't * * @param experiment Experiment object containing experiment metadata */ public void ensureStateIsDraft(Experiment experiment) { Experiment.State state = experiment.getState(); if (!state.equals(Experiment.State.DRAFT)) { throw new InvalidExperimentStateException(experiment.getID(), Experiment.State.DRAFT, experiment.getState()); } }
private void validateExperimentState(Experiment experiment) { Experiment.State state = experiment.getState(); if (!(state.equals(Experiment.State.PAUSED) || state.equals(Experiment.State.RUNNING) || state.equals(Experiment.State.DRAFT))) { Set<Experiment.State> desiredStates = new HashSet<>(); desiredStates.add(Experiment.State.DRAFT); desiredStates.add(Experiment.State.PAUSED); desiredStates.add(Experiment.State.RUNNING); throw new InvalidExperimentStateException(experiment.getID(), desiredStates, experiment.getState()); } }
protected boolean checkMutex(Experiment experiment, Table<Experiment.ID, Experiment.Label, String> userAssignments, Map<Experiment.ID, List<Experiment.ID>> exclusivesList) { //if the experiment exists in the database and is in a valid MUTEX state if (experiment != null && (experiment.getState() == Experiment.State.RUNNING || experiment.getState() == Experiment.State.PAUSED)) { //get experiments which are mutually exclusive List<Experiment.ID> exclusiveIDs = exclusivesList.get(experiment.getID()); //get all experiments to which this user is assigned Set<Experiment.ID> preAssign = getNonNullUserAssignments(exclusivesList.get(experiment.getID()), userAssignments); //iterate over the mutex experiments for (Experiment.ID exp : exclusiveIDs) { //check if the user is in the experiment if (preAssign.contains(exp)) { //return a response that the user cannot be assigned return false; } } } return true; }
/** * {@inheritDoc} */ @Override public void updateStateIndex(Experiment experiment) { LOGGER.debug("update state index experiment {} ", experiment); try { updateStateIndex(experiment.getID(), experiment.getState() != State.DELETED ? ExperimentState.NOT_DELETED : ExperimentState.DELETED); } catch (Exception e) { LOGGER.error("update state index experiment {} ", experiment, e); throw new RepositoryException("Exception while updating state index: " + e, e); } }
private Builder(Experiment other, Integer priority) { this(other.getID()); instance.creationTime = copyDate(other.getCreationTime()); instance.modificationTime = copyDate(other.getModificationTime()); instance.setDescription(other.getDescription()); instance.setSamplingPercent(other.getSamplingPercent()); instance.setRule(other.getRule()); instance.setStartTime(copyDate(other.getStartTime())); instance.setEndTime(copyDate(other.getEndTime())); instance.setState(other.getState()); instance.setLabel(other.getLabel()); instance.setApplicationName(other.getApplicationName()); instance.setPriority(priority); instance.setIsPersonalizationEnabled(other.getIsPersonalizationEnabled()); instance.setModelName(other.getModelName()); instance.setModelVersion(other.getModelVersion()); instance.isRapidExperiment = other.getIsRapidExperiment(); instance.userCap = other.getUserCap(); instance.creatorID = other.getCreatorID(); instance.tags = other.getTags(); }
/** * {@inheritDoc} */ @Override public void updateExperimentState(final Experiment experiment, final Experiment.State state) { try { cassandraRepository.updateExperimentState(experiment, state); // To maintain consistency, revert the changes made in cassandra in case the mysql update fails try { databaseRepository.updateExperimentState(experiment, state); } catch (Exception exception) { cassandraRepository.updateExperimentState(experiment, experiment.getState()); throw exception; } eventLog.postEvent(new ExperimentChangeEvent(experiment, "state", experiment.getState().toString(), state.toString())); } catch (Exception exception) { LOGGER.error("Updating experiment state for experiment:{} failed with error:", experiment, exception); throw exception; } LOGGER.info("event=EXPERIMENT_METADATA_CHANGE, message=EXPERIMENT_STATE_UPDATED, applicationName={}, configuration=[experimentName={}, oldState={}, newState={}]", experiment.getApplicationName(), experiment.getLabel(), experiment.getState(), state); } }
private Application.Name getApplicationNameForModifyingPages(Experiment.ID experimentID) { Experiment experiment = experiments.getExperiment(experimentID); // Throw an exception if the experiment is not found if (experiment == null) { throw new ExperimentNotFoundException(experimentID); } Application.Name applicationName = experiment.getApplicationName(); // Throw an exception if the experiment is in a TERMINATED state if (experiment.getState() == TERMINATED) { throw new InvalidExperimentStateException("Experiment must be in DRAFT, RUNNING or PAUSED states\"" + experimentID); } // Throw an exception if the experiment's end time has passed if (experiment.getEndTime().before(NOW)) { throw new IllegalArgumentException("Cannot modify pages of the experiment \"" + experimentID + "\" that has passed its end time"); } return applicationName; }
/** * {@inheritDoc} */ @Override public Table<Experiment.ID, Experiment.Label, Experiment> getExperimentList(Application.Name appName) { try { List<com.intuit.wasabi.repository.cassandra.pojo.Experiment> experimentPojos = experimentAccessor.getExperimentByAppName(appName.toString()).all(); Table<Experiment.ID, Experiment.Label, Experiment> result = HashBasedTable.create(); for (com.intuit.wasabi.repository.cassandra.pojo.Experiment experimentPojo : experimentPojos) { Experiment experiment = ExperimentHelper.makeExperiment(experimentPojo); if (experiment.getState() != State.TERMINATED && experiment.getState() != State.DELETED) { result.put(experiment.getID(), experiment.getLabel(), experiment); } } return result; } catch (Exception e) { throw new RepositoryException("Could not retrieve experiment list " + appName.toString() + "because: " + e, e); } }
/** * {@inheritDoc} */ @Override public void checkForIllegalPausedRunningUpdate(Experiment experiment, Experiment updates) { /* Throw an exception if the experiment is in RUNNING/PAUSED state and if applicationName or Label is being updated. Also, if startTime/endTime is being updated with a value that has already passed or when the established startTime/endTime has already passed. */ if (experiment.getState().equals(RUNNING) || experiment.getState().equals(PAUSED)) { if (updates.getApplicationName() != null && !updates.getApplicationName().equals(experiment.getApplicationName())) throw new IllegalArgumentException("Cannot change AppName when the experiment is not in DRAFT state"); if (updates.getLabel() != null && !updates.getLabel().equals(experiment.getLabel())) throw new IllegalArgumentException("Cannot change Label when the experiment is not in DRAFT state"); if (updates.getStartTime() != null && !updates.getStartTime().equals(experiment.getStartTime())) checkForIllegalExperimentStartTime(experiment, updates); if (updates.getEndTime() != null && !updates.getEndTime().equals(experiment.getEndTime())) checkForIllegalExperimentEndTime(experiment, updates); } }
/** * Creates the ExperimentDetail with a given Experiment and the total number of users. * * @param exp the experiment that provides the basic information */ public ExperimentDetail(Experiment exp) { this(exp.getID(), exp.getState(), exp.getLabel(), exp.getApplicationName(), exp.getModificationTime(), exp.getStartTime(), exp.getEndTime(), exp.getDescription(), exp.getTags()); }
private void checkBucketConstraint(Experiment experiment, Bucket newBucket) { Bucket test = cassandraRepository.getBucket(newBucket.getExperimentID(), newBucket.getLabel()); if (test != null) { throw new ConstraintViolationException(ConstraintViolationException.Reason.UNIQUE_CONSTRAINT_VIOLATION, "Bucket label must be unique within an experiment", null); } if (!experiment.getState().equals(Experiment.State.DRAFT) && newBucket.isControl() != null && newBucket.isControl()) { throw new ConstraintViolationException(ConstraintViolationException.Reason.APPLICATION_CONSTRAINT_VIOLATION, "Bucket added to a running experiment may not be a control bucket", null); } }
/** * {@inheritDoc} */ @Override public Experiment updateExperimentState(Experiment experiment, State state) { LOGGER.debug("Updating experiment {} state {} ", new Object[]{experiment, state}); validator.validateExperiment(experiment); try { // Note that this timestamp gets serialized as mulliseconds from // the epoch, so timezone is irrelevant final Date NOW = new Date(); experimentAccessor.updateExperiment(state.name(), NOW, experiment.getID().getRawID()); experiment = Experiment.from(experiment).withState(state).build(); // Point the experiment index to this experiment updateExperimentLabelIndex(experiment.getID(), experiment.getApplicationName(), experiment.getLabel(), experiment.getStartTime(), experiment.getEndTime(), experiment.getState()); updateStateIndex(experiment); } catch (Exception e) { LOGGER.error("Error while updating experiment {} state {} ", new Object[]{experiment, state}, e); throw new RepositoryException("Could not update experiment with ID \"" + experiment.getID() + "\"" + " to state " + state.toString(), e); } return experiment; }
/** * {@inheritDoc} */ @Override public BucketList adjustAllocationPercentages(Experiment experiment, Bucket newBucket) { double remainingAlloc = 1. - newBucket.getAllocationPercent(); BucketList bucketList = buckets.getBuckets(experiment.getID(), false /* don't check experiment again */); BucketList newBuckets = new BucketList(); for (Bucket bucket : bucketList.getBuckets()) { if (bucket.getLabel().equals(newBucket.getLabel())) { continue; } double newAlloc = roundToTwo(remainingAlloc * bucket.getAllocationPercent()); LOGGER.debug("Add Bucket: setting allocation percentage for bucket " + bucket.getLabel() + " in experiment " + experiment.getID() + " to: " + newAlloc); Bucket.Builder builder = Bucket.from(bucket).withAllocationPercent(newAlloc); Bucket updatedBucket = builder.build(); newBuckets.addBucket(updatedBucket); if (!Experiment.State.DRAFT.equals(experiment.getState()) && Double.compare(bucket.getAllocationPercent(), updatedBucket.getAllocationPercent()) != 0) { // this is a system event, so no user needed eventLog.postEvent(new BucketChangeEvent(experiment, updatedBucket, "allocation", String.valueOf(bucket.getAllocationPercent()), String.valueOf(updatedBucket.getAllocationPercent()))); } } return newBuckets; }
public void validateExperiment(Experiment experiment) { Experiment.State state = experiment.getState(); if (state.equals(Experiment.State.DELETED) || state.equals(Experiment.State.TERMINATED)) { return; } validateLabel(experiment.getLabel()); validateExperimentStartEnd(experiment.getStartTime(), experiment.getEndTime()); validateSamplingPercent(experiment.getSamplingPercent()); validateExperimentRule(experiment.getRule()); validateModelNameNotNullForPersonalizedExperiments(experiment.getIsPersonalizationEnabled() , experiment.getModelName()); }
/** * {@inheritDoc} */ @Override public Bucket createBucket(Experiment.ID experimentID, Bucket newBucket, UserInfo user) { Experiment experiment = experiments.getExperiment(experimentID); if (experiment == null) { throw new ExperimentNotFoundException(experimentID); } validateExperimentState(experiment); checkBucketConstraint(experiment, newBucket); LOGGER.debug("Add Bucket: adding new bucket to running experiment" + experiment.getID()); cassandraRepository.createBucket(newBucket); try { databaseRepository.createBucket(newBucket); } catch (RepositoryException e) { cassandraRepository.deleteBucket(newBucket.getExperimentID(), newBucket.getLabel()); throw e; } //if we just created an experiment in a running experiment, update the remaining allocation percentages if (!Experiment.State.DRAFT.equals(experiment.getState())) { eventLog.postEvent(new BucketCreateEvent(user, experiment, newBucket)); BucketList updates = buckets.adjustAllocationPercentages(experiment, newBucket); buckets.updateBucketAllocBatch(experimentID, updates); } return getBucket(experimentID, newBucket.getLabel()); }
@Override public Experiment updateExperiment(Experiment experiment) throws RepositoryException { validator.validateExperiment(experiment); final String SQL = "update experiment " + "set description=?, sampling_percent=?, state=?, " + "label=?, start_time=?, end_time=?, app_name=? " + "where id=?"; int rowCount = newTransaction().update( SQL, experiment.getDescription() != null ? experiment.getDescription() : "", experiment.getSamplingPercent(), experiment.getState().toString(), experiment.getLabel().toString(), experiment.getStartTime(), experiment.getEndTime(), experiment.getApplicationName().toString(), experiment.getID()); if (rowCount > 1) { throw new RepositoryException("Concurrent updates; please retry"); } if (rowCount < 1) { throw new RepositoryException("No rows were updated"); } return experiment; }
private Builder(Experiment other, Integer priority) { this(other.getID()); instance.creationTime = copyDate(other.getCreationTime()); instance.modificationTime = copyDate(other.getModificationTime()); instance.setDescription(other.getDescription()); instance.setSamplingPercent(other.getSamplingPercent()); instance.setRule(other.getRule()); instance.setStartTime(copyDate(other.getStartTime())); instance.setEndTime(copyDate(other.getEndTime())); instance.setState(other.getState()); instance.setLabel(other.getLabel()); instance.setApplicationName(other.getApplicationName()); instance.setPriority(priority); instance.setIsPersonalizationEnabled(other.getIsPersonalizationEnabled()); instance.setModelName(other.getModelName()); instance.setModelVersion(other.getModelVersion()); instance.isRapidExperiment = other.getIsRapidExperiment(); instance.userCap = other.getUserCap(); instance.creatorID = other.getCreatorID(); instance.tags = other.getTags(); }