YARN-3836. add equals and hashCode to TimelineEntity and other classes in the data model (Li Lu via sjlee)

(cherry picked from commit 2d4a8f4563c06339717ca9410b2794754603fba3)
This commit is contained in:
Sangjin Lee 2015-07-09 20:50:48 -07:00
parent e27642abf4
commit 57d8dc2fb7
4 changed files with 192 additions and 4 deletions

View File

@ -31,11 +31,25 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
/**
* The basic timeline entity data structure for timeline service v2. Timeline
* entity objects are not thread safe and should not be accessed concurrently.
* All collection members will be initialized into empty collections. Two
* timeline entities are equal iff. their type and id are identical.
*
* All non-primitive type, non-collection members will be initialized into null.
* User should set the type and id of a timeline entity to make it valid (can be
* checked by using the {@link #isValid()} method). Callers to the getters
* should perform null checks for non-primitive type, non-collection members.
*
* Callers are recommended not to alter the returned collection objects from the
* getters.
*/
@XmlRootElement(name = "entity") @XmlRootElement(name = "entity")
@XmlAccessorType(XmlAccessType.NONE) @XmlAccessorType(XmlAccessType.NONE)
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Unstable @InterfaceStability.Unstable
public class TimelineEntity { public class TimelineEntity implements Comparable<TimelineEntity> {
protected final static String SYSTEM_INFO_KEY_PREFIX = "SYSTEM_INFO_"; protected final static String SYSTEM_INFO_KEY_PREFIX = "SYSTEM_INFO_";
@XmlRootElement(name = "identifier") @XmlRootElement(name = "identifier")
@ -77,6 +91,41 @@ public class TimelineEntity {
"type='" + type + '\'' + "type='" + type + '\'' +
", id='" + id + '\'' + "]"; ", id='" + id + '\'' + "]";
} }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result =
prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Identifier)) {
return false;
}
Identifier other = (Identifier) obj;
if (id == null) {
if (other.getId() != null) {
return false;
}
} else if (!id.equals(other.getId())) {
return false;
}
if (type == null) {
if (other.getType() != null) {
return false;
}
} else if (!type.equals(other.getType())) {
return false;
}
return true;
}
} }
private TimelineEntity real; private TimelineEntity real;
@ -471,6 +520,44 @@ public class TimelineEntity {
} }
} }
public boolean isValid() {
return (getId() != null && getType() != null);
}
// When get hashCode for a timeline entity, or check if two timeline entities
// are equal, we only compare their identifiers (id and type)
@Override
public int hashCode() {
return getIdentifier().hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof TimelineEntity))
return false;
TimelineEntity other = (TimelineEntity) obj;
return getIdentifier().equals(other.getIdentifier());
}
@Override
public int compareTo(TimelineEntity other) {
int comparison = getType().compareTo(other.getType());
if (comparison == 0) {
if (getCreatedTime() > other.getCreatedTime()) {
// Order by created time desc
return -1;
} else if (getCreatedTime() < other.getCreatedTime()) {
return 1;
} else {
return getId().compareTo(other.getId());
}
} else {
return comparison;
}
}
protected TimelineEntity getReal() { protected TimelineEntity getReal() {
return real == null ? this : real; return real == null ? this : real;
} }

View File

@ -32,7 +32,7 @@ import java.util.Map;
@XmlAccessorType(XmlAccessType.NONE) @XmlAccessorType(XmlAccessType.NONE)
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Unstable @InterfaceStability.Unstable
public class TimelineEvent { public class TimelineEvent implements Comparable<TimelineEvent> {
private String id; private String id;
private HashMap<String, Object> info = new HashMap<>(); private HashMap<String, Object> info = new HashMap<>();
private long timestamp; private long timestamp;
@ -81,4 +81,43 @@ public class TimelineEvent {
public void setTimestamp(long timestamp) { public void setTimestamp(long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public boolean isValid() {
return (id != null && timestamp != 0L);
}
@Override
public int hashCode() {
int result = (int) (timestamp ^ (timestamp >>> 32));
result = 31 * result + id.hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof TimelineEvent))
return false;
TimelineEvent event = (TimelineEvent) o;
if (timestamp != event.timestamp)
return false;
if (!id.equals(event.id)) {
return false;
}
return true;
}
@Override
public int compareTo(TimelineEvent other) {
if (timestamp > other.timestamp) {
return -1;
} else if (timestamp < other.timestamp) {
return 1;
} else {
return id.compareTo(other.id);
}
}
} }

View File

@ -124,4 +124,34 @@ public class TimelineMetric {
this.values.clear(); this.values.clear();
this.values.putAll(values); this.values.putAll(values);
} }
public boolean isValid() {
return (id != null);
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + type.hashCode();
return result;
}
// Only check if type and id are equal
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof TimelineMetric))
return false;
TimelineMetric m = (TimelineMetric) o;
if (!id.equals(m.id)) {
return false;
}
if (type != m.type) {
return false;
}
return true;
}
} }

View File

@ -100,6 +100,13 @@ public class TestTimelineServiceRecords {
} }
entity.addMetric(metric2); entity.addMetric(metric2);
TimelineMetric metric3 = new TimelineMetric(TimelineMetric.Type.SINGLE_VALUE);
metric3.setId("test metric id 1");
metric3.addValue(4L, (short) 4);
Assert.assertEquals("metric3 should equal to metric2! ", metric3, metric2);
Assert.assertNotEquals("metric1 should not equal to metric2! ",
metric1, metric2);
TimelineEvent event1 = new TimelineEvent(); TimelineEvent event1 = new TimelineEvent();
event1.setId("test event id 1"); event1.setId("test event id 1");
event1.addInfo("test info key 1", "test info value 1"); event1.addInfo("test info key 1", "test info value 1");
@ -108,7 +115,7 @@ public class TestTimelineServiceRecords {
event1.addInfo("test info key 3", true); event1.addInfo("test info key 3", true);
Assert.assertTrue( Assert.assertTrue(
event1.getInfo().get("test info key 3") instanceof Boolean); event1.getInfo().get("test info key 3") instanceof Boolean);
event1.setTimestamp(0L); event1.setTimestamp(1L);
entity.addEvent(event1); entity.addEvent(event1);
TimelineEvent event2 = new TimelineEvent(); TimelineEvent event2 = new TimelineEvent();
@ -119,9 +126,18 @@ public class TestTimelineServiceRecords {
event2.addInfo("test info key 3", true); event2.addInfo("test info key 3", true);
Assert.assertTrue( Assert.assertTrue(
event2.getInfo().get("test info key 3") instanceof Boolean); event2.getInfo().get("test info key 3") instanceof Boolean);
event2.setTimestamp(1L); event2.setTimestamp(2L);
entity.addEvent(event2); entity.addEvent(event2);
Assert.assertFalse("event1 should not equal to event2! ",
event1.equals(event2));
TimelineEvent event3 = new TimelineEvent();
event3.setId("test event id 1");
event3.setTimestamp(1L);
Assert.assertEquals("event1 should equal to event3! ", event3, event1);
Assert.assertNotEquals("event1 should not equal to event2! ",
event1, event2);
entity.setCreatedTime(0L); entity.setCreatedTime(0L);
entity.setModifiedTime(1L); entity.setModifiedTime(1L);
entity.addRelatesToEntity("test type 2", "test id 2"); entity.addRelatesToEntity("test type 2", "test id 2");
@ -136,6 +152,22 @@ public class TestTimelineServiceRecords {
TimelineEntity entity2 = new TimelineEntity(); TimelineEntity entity2 = new TimelineEntity();
entities.addEntity(entity2); entities.addEntity(entity2);
LOG.info(TimelineUtils.dumpTimelineRecordtoJSON(entities, true)); LOG.info(TimelineUtils.dumpTimelineRecordtoJSON(entities, true));
Assert.assertFalse("entity 1 should not be valid without type and id",
entity1.isValid());
entity1.setId("test id 2");
entity1.setType("test type 2");
entity2.setId("test id 1");
entity2.setType("test type 1");
Assert.assertEquals("Timeline entity should equal to entity2! ",
entity, entity2);
Assert.assertNotEquals("entity1 should not equal to entity! ",
entity1, entity);
Assert.assertEquals("entity should be less than entity1! ",
entity1.compareTo(entity), 1);
Assert.assertEquals("entity's hash code should be -28727840 but not "
+ entity.hashCode(), entity.hashCode(), -28727840);
} }
@Test @Test