use of com.google.storage.onestore.v3.OnestoreEntity.Index.Property in project appengine-java-standard by GoogleCloudPlatform.
the class LocalDatastoreService method validateAndProcessProperty.
private void validateAndProcessProperty(Property prop) {
if (RESERVED_NAME.matcher(prop.getName()).matches()) {
throw newError(ErrorCode.BAD_REQUEST, String.format("illegal property.name: %s", prop.getName()));
}
PropertyValue val = prop.getMutableValue();
if (val.hasUserValue() && !val.getUserValue().hasObfuscatedGaiaid()) {
// If not already set, populate obfuscated gaia id with hash of email address.
PropertyValue.UserValue userVal = val.getMutableUserValue();
userVal.setObfuscatedGaiaid(Integer.toString(userVal.getEmail().hashCode()));
}
}
use of com.google.storage.onestore.v3.OnestoreEntity.Index.Property in project appengine-java-standard by GoogleCloudPlatform.
the class LocalDatastoreService method createIndexEntities.
/**
* Splits a full entity into all index entities seen in a projection.
*
* @param entity the entity to split
* @param postfixProps the properties included in the postfix
* @return A list of the index entities.
*/
private ImmutableList<EntityProto> createIndexEntities(EntityProto entity, Set<String> postfixProps, EntityProtoComparator entityComparator) {
SetMultimap<String, PropertyValue> toSplit = MultimapBuilder.hashKeys(postfixProps.size()).hashSetValues(1).build();
Set<String> seen = Sets.newHashSet();
boolean splitRequired = false;
for (Property prop : entity.propertys()) {
if (postfixProps.contains(prop.getName())) {
// If we have multiple values for any postfix property, we need to split.
splitRequired |= !seen.add(prop.getName());
// Only add the value if it matches the query filters
if (entityComparator.matches(prop)) {
toSplit.put(prop.getName(), prop.getValue());
}
}
}
if (!splitRequired) {
// No need for splitting!
return ImmutableList.of(entity);
}
EntityProto clone = new EntityProto();
clone.getMutableKey().copyFrom(entity.getKey());
clone.getMutableEntityGroup();
List<EntityProto> results = Lists.newArrayList(clone);
for (Map.Entry<String, Collection<PropertyValue>> entry : toSplit.asMap().entrySet()) {
if (entry.getValue().size() == 1) {
// No need for cloning!
for (EntityProto result : results) {
result.addProperty().setName(entry.getKey()).setMeaning(Property.Meaning.INDEX_VALUE).getMutableValue().copyFrom(Iterables.getOnlyElement(entry.getValue()));
}
continue;
}
List<EntityProto> splitResults = Lists.newArrayListWithCapacity(results.size() * entry.getValue().size());
for (PropertyValue value : entry.getValue()) {
for (EntityProto result : results) {
EntityProto split = result.clone();
split.addProperty().setName(entry.getKey()).setMeaning(Property.Meaning.INDEX_VALUE).getMutableValue().copyFrom(value);
splitResults.add(split);
}
}
results = splitResults;
}
return ImmutableList.copyOf(results);
}
use of com.google.storage.onestore.v3.OnestoreEntity.Index.Property in project appengine-java-standard by GoogleCloudPlatform.
the class LocalDatastoreCostAnalysis method getEntityByPropertyIndexes.
/**
* Given a set of property names, generates a {@code List} of {@link Index} objects that can be
* used to generate index rows that would be appear in EntitiesByProperty and
* EntitiesByPropertyDesc
*
* @param propertyNames The property names.
* @return The indexes.
*/
static List<Index> getEntityByPropertyIndexes(Set<String> propertyNames) {
List<String> sortedPropertyNames = Ordering.natural().sortedCopy(propertyNames);
List<Index> indexes = Lists.newArrayList();
for (String propName : sortedPropertyNames) {
// EnititiesByProperty
Index index = new Index();
index.addProperty(new Index.Property().setName(propName).setDirection(Direction.ASCENDING));
indexes.add(index);
// EnititiesByPropertyDesc
index = new Index();
index.addProperty(new Index.Property().setName(propName).setDirection(Direction.DESCENDING));
indexes.add(index);
}
return indexes;
}
use of com.google.storage.onestore.v3.OnestoreEntity.Index.Property in project appengine-java-standard by GoogleCloudPlatform.
the class LocalDatastoreCostAnalysis method changedIndexRows.
/**
* Determine the number of index rows that need to change when writing {@code newEntity}, assuming
* {@code oldEntity} represents the current state of the Datastore.
*
* @param oldEntity Entity representing the current state in the datastore.
* @param newEntity Entity representing the desired state in the datastore.
* @return The number of index rows that need to change.
*/
private int changedIndexRows(EntityProto oldEntity, EntityProto newEntity) {
// All properties that are unique within the old entity, not all properties that are unique
// to the old entity. Declaring the specific subtype because we rely on the fact that
// HashMultimap enforces uniqueness of key-value pairs.
SetMultimap<String, Property> uniqueOldProperties = HashMultimap.create();
if (oldEntity != null) {
for (Property oldProp : oldEntity.propertys()) {
// A given name may only have one property value on the old entity but multiple values on
// the new entity. If that's the case, two Properties that are equal will be considered not
// equal due to different values of the "multiple" attribute. We want these Properties to be
// considered equal so we hard-code "multiple" to be false in the map.
oldProp = oldProp.isMultiple() ? oldProp.clone().setMultiple(false) : oldProp;
uniqueOldProperties.put(oldProp.getName(), oldProp);
}
}
// All properties that are unique within the new entity, not all properties that are unique
// to the new entity. Declaring the specific subtype because we rely on the fact that
// HashMultimap enforces uniqueness of key-value pairs.
SetMultimap<String, Property> uniqueNewProperties = HashMultimap.create();
// Number of properties per name that have not changed between old and new.
Multiset<String> unchanged = HashMultiset.create();
for (Property newProp : newEntity.propertys()) {
// See the comment in the loop where we populate uniqueOldProperties for an explanation of why
// we do this.
newProp = newProp.isMultiple() ? newProp.clone().setMultiple(false) : newProp;
uniqueNewProperties.put(newProp.getName(), newProp);
if (uniqueOldProperties.containsEntry(newProp.getName(), newProp)) {
unchanged.add(newProp.getName());
}
}
// We're going to build Index objects that correspond to the single-property, built-in indexes
// that the Datastore maintains. In order to do this we need a unique list of all the property
// names on both the old and new entities.
Set<String> allPropertyNames = Sets.newHashSet(Iterables.concat(uniqueOldProperties.keySet(), uniqueNewProperties.keySet()));
Iterable<Index> allIndexes = Iterables.concat(indexManager.getIndexesForKind(Utils.getKind(newEntity.getKey())), getEntityByPropertyIndexes(allPropertyNames));
Multiset<String> uniqueOldPropertyNames = uniqueOldProperties.keys();
Multiset<String> uniqueNewPropertyNames = uniqueNewProperties.keys();
int pathSize = newEntity.getKey().getPath().elementSize();
int writes = 0;
for (Index index : allIndexes) {
// Take ancestor indexes into account.
// Ancestor doesn't matter for EntityByProperty indexes, and these are the only indexes that
// have a single property.
int ancestorMultiplier = index.isAncestor() && index.propertySize() > 1 ? pathSize : 1;
writes += (calculateWritesForCompositeIndex(index, uniqueOldPropertyNames, uniqueNewPropertyNames, unchanged) * ancestorMultiplier);
}
return writes;
}
use of com.google.storage.onestore.v3.OnestoreEntity.Index.Property in project appengine-java-standard by GoogleCloudPlatform.
the class EntityStorageConversions method stashProperties.
/**
* Finds all properties marked for stashing: if they are computed, removes them, moves them to raw
* properties.
*
* @param diskEntity The EntityProto to modify.
*/
private static void stashProperties(EntityProto diskEntity) {
ImmutableList<Property> properties = ImmutableList.copyOf(diskEntity.propertys());
diskEntity.clearProperty();
for (Property property : properties) {
if (property.hasStashed()) {
if (!property.isComputed()) {
diskEntity.addRawProperty(property);
}
} else {
diskEntity.addProperty(property);
}
}
}
Aggregations