/** * VMware Continuent Tungsten Replicator * Copyright (C) 2015 VMware, Inc. All rights reserved. * * 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. * * Initial developer(s): * Contributor(s): */ package com.continuent.tungsten.common.patterns.order; import java.io.Serializable; /** * A HighWater resource allows to represent and compare replicators applied * event IDs. It is especially used by session consistency/smart-scale to * compared master and slave progresses.<br> * It is composed of a epoch and a event id. The string representation being * <epoch>(<eventId>) * * @author <a href="mailto:edward.archibald@continuent.com">Edward Archibald</a> */ public class HighWaterResource implements Serializable, Comparable<HighWaterResource> { /** * */ private static final long serialVersionUID = 1L; private long highWaterEpoch = -1; private String highWaterEventId = ""; /** New event ids are in the form "<log file #>:<offset>;<sessionId>" */ private static final String SESSION_DELIMITER = ";"; public HighWaterResource() { } public HighWaterResource(long epoch, String eventId) { this.highWaterEpoch = epoch; this.highWaterEventId = eventId; } public HighWaterResource(String resourceAsString) { String epochStr = resourceAsString.substring(0, resourceAsString.indexOf('(')); this.highWaterEpoch = Long.valueOf(epochStr); this.highWaterEventId = resourceAsString.substring( resourceAsString.indexOf('(') + 1, resourceAsString.length() - 1); } /** * Whether this HW is initialized * * @return true if this HW's epoch is 0 or more */ public boolean isInitialized() { return highWaterEpoch >= 0; } /** * Compare ourselves to what is passed in.<br> * Two uninitialized HW will be equal<br> * An uninitialized HW is always older than an initialized one Epochs * comparison is made first, then the offset. Session Ids, if any are * ignored * * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(HighWaterResource o) { // Two uninitialized HW are equal if (!this.isInitialized() && !o.isInitialized()) return 0; // An uninitialized HW is always the oldest if (!this.isInitialized()) return -1; if (!o.isInitialized()) return 1; if (this.highWaterEpoch > o.getHighWaterEpoch()) return 1; else if (this.highWaterEpoch < o.getHighWaterEpoch()) return -1; else { String oToCompare = o.getHighWaterEventId(); String thisToCompare = this.highWaterEventId; int sessionDelimiter; if ((sessionDelimiter = o.highWaterEventId .indexOf(SESSION_DELIMITER)) != -1) { oToCompare = o.getHighWaterEventId().substring(0, sessionDelimiter); } else { oToCompare = o.getHighWaterEventId(); } if ((sessionDelimiter = this.highWaterEventId .indexOf(SESSION_DELIMITER)) != -1) { thisToCompare = this.highWaterEventId.substring(0, sessionDelimiter); } else { thisToCompare = this.highWaterEventId; } if (oToCompare.length() == 0 && thisToCompare.length() > 0) { return 1; } else if (thisToCompare.length() == 0 && oToCompare.length() > 0) { return -1; } return (thisToCompare.compareTo(oToCompare)); } } @Override public boolean equals(Object obj) { if (obj == null || !(obj instanceof HighWaterResource)) return false; return this.compareTo((HighWaterResource) obj) == 0; } public void update(long epoch, String eventId) { this.highWaterEpoch = epoch; this.highWaterEventId = eventId; } public String toString() { return String.format("%d(%s)", highWaterEpoch, highWaterEventId); } public static String getSessionId(String eventId) { int sessionDelimiter; if ((sessionDelimiter = eventId.indexOf(SESSION_DELIMITER)) != -1) { return eventId.substring(sessionDelimiter + 1); } return null; } public long getHighWaterEpoch() { return highWaterEpoch; } public void setHighWaterEpoch(long highWaterEpoch) { this.highWaterEpoch = highWaterEpoch; } public String getHighWaterEventId() { return highWaterEventId; } public void setHighWaterEventId(String highWaterEventId) { this.highWaterEventId = highWaterEventId; } }