private Builder(Bucket other) { instance = new Bucket(); instance.experimentID = other.getExperimentID(); instance.label = other.getLabel(); instance.control = other.isControl() == null ? Boolean.FALSE : other.isControl(); instance.allocationPercent = other.getAllocationPercent(); instance.description = other.getDescription(); instance.payload = other.getPayload(); instance.state = other.getState(); }
public Bucket build() { Bucket result = new Bucket(); result.setControl(instance.isControl()); result.setState(instance.getState()); result.setLabel(instance.getLabel()); result.setPayload(instance.getPayload()); result.setAllocationPercent(instance.getAllocationPercent()); result.setDescription(instance.getDescription()); result.setExperimentID(instance.getExperimentID()); instance = null; return result; } }
/** * {@inheritDoc} */ @Override public void validateBucketChanges(Bucket bucket, Bucket updates) { if (updates.getExperimentID() != null && !updates.getExperimentID().equals(bucket.getExperimentID())) { throw new IllegalArgumentException("Invalid value for experimentID \"" + updates.getExperimentID() + " \"." + " Cannot update ExperimentID"); } if (updates.getLabel() != null && !updates.getLabel().equals(bucket.getLabel())) { throw new IllegalArgumentException("Invalid value for bucket label \"" + updates.getLabel() + " \". " + "Cannot update bucket label"); } if (updates.getState() != null && !updates.getState().equals(bucket.getState())) { throw new IllegalArgumentException("Cannot update the state of a bucket using this api"); } }
/** * This method takes a list of buckets and transforms it to the {@link BucketDetail}s that are needed * for later extension. * * @param buckets a list of {@link Bucket}s */ public void addBuckets(List<Bucket> buckets) { List<BucketDetail> details = buckets.stream() .map(b -> new BucketDetail(b.getLabel(), b.isControl(), b.getAllocationPercent(), b.getState(), b.getDescription())) .collect(Collectors.toList()); setBuckets(details); }
/** * {@inheritDoc} */ @Override public Bucket updateBucketAllocationPercentage(Bucket bucket, Double desiredAllocationPercentage) { try { bucketAccessor.updateAllocation(desiredAllocationPercentage, bucket.getExperimentID().getRawID(), bucket.getLabel().toString()); } catch (Exception e) { throw new RepositoryException("Could not update bucket allocation percentage \"" + bucket.getExperimentID() + "\".\"" + bucket.getLabel() + "\"", e); } // return the bucket with the updated values bucket = getBucket(bucket.getExperimentID(), bucket.getLabel()); return bucket; }
/** * Get the bucket based on experiment id and bucket label * If metadata cache is enabled then fetch from cache else fetch from database. * * @param experimentID * @param bucketLabel * @return */ protected Optional<Bucket> getBucketByLabel(Experiment.ID experimentID, Bucket.Label bucketLabel) { Optional<Bucket> rBucket = Optional.empty(); BucketList bucketList = null; if (metadataCacheEnabled) { bucketList = metadataCache.getBucketList(experimentID); } else { bucketList = repository.getBucketList(experimentID); } if (isNull(bucketList)) return rBucket; for (Bucket bucket : bucketList.getBuckets()) { if (bucket.getLabel().equals(bucketLabel)) { return Optional.of(bucket); } } return rBucket; }
/** * @param bucket bucket to update * @param desiredAllocationPercentage allocation information * @return bucket that were passed in???? * @throws RepositoryException */ @Override public Bucket updateBucketAllocationPercentage(Bucket bucket, Double desiredAllocationPercentage) throws RepositoryException { final String SQL = "update bucket " + "set allocation_percent=? " + "where experiment_id=? and label=?"; newTransaction().update( SQL, desiredAllocationPercentage.toString(), bucket.getExperimentID(), bucket.getLabel().toString()); return bucket; }
/** * {@inheritDoc} */ @Override public BucketList combineOldAndNewBuckets(BucketList oldBuckets, BucketList newBuckets) { BucketList allBuckets = new BucketList(); for (Bucket b : oldBuckets.getBuckets()) { Boolean changed = false; for (Bucket bb : newBuckets.getBuckets()) { if (bb.getLabel().equals(b.getLabel())) { allBuckets.addBucket(bb); changed = true; break; } } if (!changed) { allBuckets.addBucket(b); } } return allBuckets; } }
@Override public Bucket updateBucketState(Bucket bucket, Bucket.State desiredState) throws RepositoryException { final String SQL = "update bucket " + "set state = ? " + "where experiment_id=? and label=?"; newTransaction().update( SQL, desiredState.toString(), bucket.getExperimentID(), bucket.getLabel().toString()); return bucket; }
/** * {@inheritDoc} */ @Override public Bucket updateBucketState(Bucket bucket, Bucket.State desiredState) { LOGGER.debug("Updating bucket {} state {}", new Object[]{bucket, desiredState}); try { bucketAccessor.updateState(desiredState.name(), bucket .getExperimentID().getRawID(), bucket.getLabel().toString()); Result<com.intuit.wasabi.repository.cassandra.pojo.Bucket> bucketPojo = bucketAccessor.getBucketByExperimentIdAndBucket(bucket.getExperimentID() .getRawID(), bucket.getLabel().toString()); return BucketHelper.makeBucket(bucketPojo.one()); } catch (Exception e) { LOGGER.error("Error while updating bucket {} state {}", new Object[]{bucket, desiredState}, e); throw new RepositoryException("Exception while updating bucket state " + bucket + " state " + desiredState, e); } }
/** * {@inheritDoc} */ @Override public void createBucket(Bucket newBucket) { LOGGER.debug("Creating bucket {}", newBucket); Preconditions.checkNotNull(newBucket, "Parameter \"newBucket\" cannot be null"); final Bucket.State STATE = Bucket.State.OPEN; try { bucketAccessor.insert(newBucket.getExperimentID().getRawID(), newBucket.getLabel().toString(), newBucket.getDescription(), newBucket.getAllocationPercent(), newBucket.isControl(), newBucket.getPayload(), STATE.name()); } catch (Exception e) { LOGGER.error("Error creating bucket {}", newBucket, e); throw new RepositoryException("Could not create bucket \"" + newBucket + "\" because " + e, e); } }
/** * This method finds the right attributes to set. The set fields can be found * in the {@link TextTemplates}. * * @param buckEvent an {@link BucketChangeEvent} that represents the changes * @return the message for the email */ private String getBucketChangedMessage(BucketChangeEvent buckEvent) { ST template = new ST(BUCKET_CHANGE); Map<String, String> variables = new HashMap<>(); Bucket buck = buckEvent.getBucket(); ExperimentBase exp = buckEvent.getExperiment(); put(variables, EXPERIMENT_LABEL, exp.getLabel()); put(variables, BUCKET_NAME, buck.getLabel().toString()); put(variables, APPLICATION_NAME, String.valueOf(exp.getApplicationName())); put(variables, USER_NAME, getUserRepresentation(buckEvent.getUser())); put(variables, FIELD_NAME, buckEvent.getPropertyName()); if (buckEvent.getPropertyName() != null && "allocation".equalsIgnoreCase(buckEvent.getPropertyName())) { put(variables, FIELD_BEFORE, String.valueOf(((double) Math.round(Double.parseDouble(buckEvent.getBefore()) * 10000d) / 10000d) * 100).concat("%")); put(variables, FIELD_AFTER, String.valueOf(((double) Math.round(Double.parseDouble(buckEvent.getAfter()) * 10000d) / 10000d) * 100).concat("%")); } else { put(variables, FIELD_BEFORE, buckEvent.getBefore()); put(variables, FIELD_AFTER, buckEvent.getAfter()); } return replaceVariablesInTemplate(variables, template); }
/** * {@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; }
bucketAccessor.updateControl(false, currentBucket.getExperimentID().getRawID(), currentBucket.getLabel().toString())); bucket.getPayload() != null ? bucket.getPayload() : "", bucket.getExperimentID().getRawID(), bucket.getLabel().toString()); throw new RepositoryException("Could not update bucket \"" + bucket.getExperimentID() + "\".\"" + bucket.getLabel() + "\"", e);
private Builder(Bucket other) { instance = new Bucket(); instance.experimentID = other.getExperimentID(); instance.label = other.getLabel(); instance.control = other.isControl() == null ? Boolean.FALSE : other.isControl(); instance.allocationPercent = other.getAllocationPercent(); instance.description = other.getDescription(); instance.payload = other.getPayload(); instance.state = other.getState(); }
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); } }
/** * This method finds the right attributes to set. The set fields can be found * in the {@link TextTemplates}. * * @param buckEvent an {@link BucketCreateEvent} that represents the changes * @return the message for the email */ private String getBucketCreatedMessage(BucketCreateEvent buckEvent) { ST template = new ST(BUCKET_CREATED); Map<String, String> variables = new HashMap<>(); Bucket buck = buckEvent.getBucket(); ExperimentBase exp = buckEvent.getExperiment(); put(variables, EXPERIMENT_LABEL, exp.getLabel()); put(variables, BUCKET_NAME, buck.getLabel().toString()); put(variables, APPLICATION_NAME, String.valueOf(exp.getApplicationName())); put(variables, USER_NAME, getUserRepresentation(buckEvent.getUser())); return replaceVariablesInTemplate(variables, template); }
/** * {@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()); }
public Bucket build() { Bucket result = new Bucket(); result.setControl(instance.isControl()); result.setState(instance.getState()); result.setLabel(instance.getLabel()); result.setPayload(instance.getPayload()); result.setAllocationPercent(instance.getAllocationPercent()); result.setDescription(instance.getDescription()); result.setExperimentID(instance.getExperimentID()); instance = null; return result; } }
@Override public void createBucket(Bucket newBucket) throws RepositoryException { final String SQL = "insert into bucket (" + "experiment_id, description, label, allocation_percent, is_control, payload, state) " + "values (?,?,?,?,?,?,?)"; try { newTransaction().insert( SQL, newBucket.getExperimentID(), newBucket.getDescription() != null ? newBucket.getDescription() : "", newBucket.getLabel().toString(), newBucket.getAllocationPercent(), newBucket.isControl() != null ? newBucket.isControl() : false, newBucket.getPayload() != null ? newBucket.getPayload() : "", Bucket.State.OPEN.toString()); } catch (WasabiException e) { throw e; } catch (Exception e) { throw new RepositoryException("Could not create bucket \"" + newBucket + "\"", e); } }