blob: 520f17d6c0284e78febb38fbab7bda35c2e28c9d [file] [log] [blame]
package org.apache.helix.model;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.helix.HelixProperty;
import org.apache.helix.ZNRecord;
import org.apache.helix.model.Message.MessageType;
import org.apache.helix.model.builder.ConstraintItemBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* All of the constraints on a given cluster and its subcomponents, both physical and logical.
*/
public class ClusterConstraints extends HelixProperty {
private static Logger LOG = LoggerFactory.getLogger(ClusterConstraints.class);
/**
* Attributes on which constraints operate
*/
public enum ConstraintAttribute {
STATE,
MESSAGE_TYPE,
TRANSITION,
RESOURCE,
PARTITION,
INSTANCE,
CONSTRAINT_VALUE
}
/**
* Possible special values that constraint attributes can take
*/
public enum ConstraintValue {
ANY
}
/**
* What is being constrained
*/
public enum ConstraintType {
STATE_CONSTRAINT,
MESSAGE_CONSTRAINT
}
// constraint-id -> constraint-item
private final Map<String, ConstraintItem> _constraints = new HashMap<String, ConstraintItem>();
/**
* Instantiate constraints as a given type
* @param type {@link ConstraintType} representing what this constrains
*/
public ClusterConstraints(ConstraintType type) {
super(type.toString());
}
/**
* Instantiate constraints from a pre-populated ZNRecord
* @param record ZNRecord containing all constraints
*/
public ClusterConstraints(ZNRecord record) {
super(record);
for (String constraintId : _record.getMapFields().keySet()) {
ConstraintItemBuilder builder = new ConstraintItemBuilder();
ConstraintItem item =
builder.addConstraintAttributes(_record.getMapField(constraintId)).build();
// ignore item with empty attributes or no constraint-value
if (item.getAttributes().size() > 0 && item.getConstraintValue() != null) {
addConstraintItem(constraintId, item);
} else {
LOG.error("Skip invalid constraint. key: " + constraintId + ", value: "
+ _record.getMapField(constraintId));
}
}
}
/**
* add the constraint, overwrite existing one if constraint with same constraint-id already exists
* @param constraintId unique constraint identifier
* @param item the constraint as a {@link ConstraintItem}
*/
public void addConstraintItem(String constraintId, ConstraintItem item) {
Map<String, String> map = new TreeMap<String, String>();
for (ConstraintAttribute attr : item.getAttributes().keySet()) {
map.put(attr.toString(), item.getAttributeValue(attr));
}
map.put(ConstraintAttribute.CONSTRAINT_VALUE.toString(), item.getConstraintValue());
_record.setMapField(constraintId, map);
_constraints.put(constraintId, item);
}
/**
* Add multiple constraint items.
* @param items (constraint identifier, {@link ConstrantItem}) pairs
*/
public void addConstraintItems(Map<String, ConstraintItem> items) {
for (String constraintId : items.keySet()) {
addConstraintItem(constraintId, items.get(constraintId));
}
}
/**
* remove a constraint-item
* @param constraintId unique constraint identifier
*/
public void removeConstraintItem(String constraintId) {
_constraints.remove(constraintId);
_record.getMapFields().remove(constraintId);
}
/**
* get a constraint-item
* @param constraintId unique constraint identifier
* @return {@link ConstraintItem} or null if not present
*/
public ConstraintItem getConstraintItem(String constraintId) {
return _constraints.get(constraintId);
}
/**
* return a set of constraints that match the attribute pairs
* @param attributes (constraint scope, constraint string) pairs
* @return a set of {@link ConstraintItem}s with matching attributes
*/
public Set<ConstraintItem> match(Map<ConstraintAttribute, String> attributes) {
Set<ConstraintItem> matches = new HashSet<ConstraintItem>();
for (ConstraintItem item : _constraints.values()) {
if (item.match(attributes)) {
matches.add(item);
}
}
return matches;
}
/**
* convert a message to constraint attribute pairs
* @param msg a {@link Message} containing constraint attributes
* @return constraint attribute scope-value pairs
*/
public static Map<ConstraintAttribute, String> toConstraintAttributes(Message msg) {
Map<ConstraintAttribute, String> attributes = new TreeMap<ConstraintAttribute, String>();
String msgType = msg.getMsgType();
attributes.put(ConstraintAttribute.MESSAGE_TYPE, msgType);
if (MessageType.STATE_TRANSITION.name().equals(msgType)) {
if (msg.getFromState() != null && msg.getToState() != null) {
attributes.put(ConstraintAttribute.TRANSITION, msg.getFromState() + "-" + msg.getToState());
}
if (msg.getResourceName() != null) {
attributes.put(ConstraintAttribute.RESOURCE, msg.getResourceName());
}
if (msg.getTgtName() != null) {
attributes.put(ConstraintAttribute.INSTANCE, msg.getTgtName());
}
if (msg.getPartitionName() != null) {
attributes.put(ConstraintAttribute.PARTITION, msg.getPartitionName());
}
}
return attributes;
}
@Override
public boolean isValid() {
// TODO Auto-generated method stub
return true;
}
}