com.google.appengine.tools.pipeline.impl.model.Barrier Maven / Gradle / Ivy
Show all versions of appengine-pipeline Show documentation
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
package com.google.appengine.tools.pipeline.impl.model;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.tools.pipeline.impl.util.StringUtils;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* A {@code Barrier} represents a list of slots that need to be filled before
* something is allowed to happen.
*
* There are two types of barriers, run barriers and finalize barriers. A run
* barrier is used to trigger the running of a job. Its list of slots represent
* arguments to the job. A finalize barrier is used to trigger the finalization
* of a job. It has only one slot which is used as the output value of the job.
* The essential properties are:
*
* - type: Either run or finalize
*
- jobKey: The datastore key of the associated job
*
- waitingOn: A list of the datastore keys of the slots for which this
* barrier is waiting
*
- released: A boolean representing whether or not this barrier is released.
* Released means that all of the slots are filled and so the action associated
* with this barrier should be triggered.
*
*
* @author [email protected] (Mitch Rudominer)
*
*/
public class Barrier extends PipelineModelObject {
/**
* The type of Barrier
*/
public static enum Type {
RUN, FINALIZE
}
public static final String DATA_STORE_KIND = "pipeline-barrier";
private static final String TYPE_PROPERTY = "barrierType";
private static final String JOB_KEY_PROPERTY = "jobKey";
private static final String RELEASED_PROPERTY = "released";
private static final String WAITING_ON_KEYS_PROPERTY = "waitingOnKeys";
private static final String WAITING_ON_GROUP_SIZES_PROPERTY = "waitingOnGroupSizes";
// persistent
private final Type type;
private final Key jobKey;
private boolean released;
private final List waitingOnKeys;
private final List waitingOnGroupSizes;
// transient
private List waitingOnInflated;
/**
* Returns the entity group parent of a Barrier of the specified type.
*
* According to our transactional
* model: If B is the finalize barrier of a Job J, then the entity group
* parent of B is J. Run barriers do not have an entity group parent.
*/
private static Key getEgParentKey(Type type, Key jobKey) {
switch (type) {
case RUN:
return null;
case FINALIZE:
if (null == jobKey) {
throw new IllegalArgumentException("jobKey is null");
}
break;
}
return jobKey;
}
private Barrier(Type type, Key rootJobKey, Key jobKey, Key generatorJobKey, String graphGUID) {
super(rootJobKey, getEgParentKey(type, jobKey), null, generatorJobKey, graphGUID);
this.jobKey = jobKey;
this.type = type;
waitingOnGroupSizes = new LinkedList<>();
waitingOnInflated = new LinkedList<>();
waitingOnKeys = new LinkedList<>();
}
public static Barrier dummyInstanceForTesting() {
Key dummyKey = KeyFactory.createKey("dummy", "dummy");
return new Barrier(Type.RUN, dummyKey, dummyKey, dummyKey, "abc");
}
public Barrier(Type type, JobRecord jobRecord) {
this(type, jobRecord.getRootJobKey(), jobRecord.getKey(), jobRecord.getGeneratorJobKey(),
jobRecord.getGraphGuid());
}
public Barrier(Entity entity) {
super(entity);
jobKey = (Key) entity.getProperty(JOB_KEY_PROPERTY);
type = Type.valueOf((String) entity.getProperty(TYPE_PROPERTY));
released = (Boolean) entity.getProperty(RELEASED_PROPERTY);
waitingOnKeys = getListProperty(WAITING_ON_KEYS_PROPERTY, entity);
waitingOnGroupSizes = getListProperty(WAITING_ON_GROUP_SIZES_PROPERTY, entity);
}
@Override
public Entity toEntity() {
Entity entity = toProtoEntity();
entity.setProperty(JOB_KEY_PROPERTY, jobKey);
entity.setUnindexedProperty(TYPE_PROPERTY, type.toString());
entity.setUnindexedProperty(RELEASED_PROPERTY, released);
entity.setUnindexedProperty(WAITING_ON_KEYS_PROPERTY, waitingOnKeys);
entity.setUnindexedProperty(WAITING_ON_GROUP_SIZES_PROPERTY, waitingOnGroupSizes);
return entity;
}
@Override
protected String getDatastoreKind() {
return DATA_STORE_KIND;
}
public void inflate(Map pool) {
int numSlots = waitingOnKeys.size();
waitingOnInflated = new ArrayList<>(numSlots);
for (int i = 0; i < numSlots; i++) {
Key key = waitingOnKeys.get(i);
int groupSize = waitingOnGroupSizes.get(i).intValue();
Slot slot = pool.get(key);
if (null == slot) {
throw new RuntimeException("No slot in pool with key=" + key);
}
SlotDescriptor descriptor = new SlotDescriptor(slot, groupSize);
waitingOnInflated.add(descriptor);
}
}
public Key getJobKey() {
return jobKey;
}
public Type getType() {
return type;
}
public boolean isReleased() {
return released;
}
public void setReleased() {
released = true;
}
public List getWaitingOnKeys() {
return waitingOnKeys;
}
/**
* May return null if this Barrier has not been inflated
*/
public List getWaitingOnInflated() {
return waitingOnInflated;
}
public Object[] buildArgumentArray() {
List