
net.wicp.tams.commons.binlog.GtidSet Maven / Gradle / Ivy
/*
* Copyright 2015 Stanley Shyiko
*
* 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 net.wicp.tams.commons.binlog;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* GTIDGTID set as described
* https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html
*
* @author Administrator
*
*/
public class GtidSet {
private final Map map = new LinkedHashMap();
/**
* @param isSimple
* 是否支持简写
* @param gtidSet
* gtid set comprised of closed intervals (like MySQL's
* executed_gtid_set).
*/
public GtidSet(String gtidSet, boolean isSimple) {
gtidSet = gtidSet.replace("\n", "");
String[] uuidSets = gtidSet.isEmpty() ? new String[0] : gtidSet.split(",");
for (String uuidSet : uuidSets) {
int uuidSeparatorIndex = uuidSet.indexOf(":");
String sourceId = uuidSet.substring(0, uuidSeparatorIndex);
List intervals = new ArrayList();
String[] rawIntervals = uuidSet.substring(uuidSeparatorIndex + 1).split(":");
for (String interval : rawIntervals) {
String[] is = interval.split("-");
long[] split = new long[is.length];
for (int i = 0, e = is.length; i < e; i++) {
split[i] = Long.parseLong(is[i]);
}
if (split.length == 1) {
if (isSimple) {
split = new long[] { 1L, split[0] };
} else {
split = new long[] { split[0], split[0] };
}
}
intervals.add(new Interval(split[0], split[1]));
}
map.put(sourceId, new UUIDSet(sourceId, intervals));
}
}
public GtidSet(String gtidSet) {
this(gtidSet, true);
}
public Collection getUUIDSets() {
return map.values();
}
/**
* @param gtid
* GTID ("source_id:transaction_id")
* @return whether or not gtid was added to the set (false if it was already
* there)
*/
public boolean add(String gtid) {
String[] split = gtid.split(":");
String sourceId = split[0];
long transactionId = Long.parseLong(split[1]);
UUIDSet uuidSet = map.get(sourceId);
if (uuidSet == null) {
map.put(sourceId, uuidSet = new UUIDSet(sourceId, new ArrayList()));
}
List intervals = (List) uuidSet.intervals;
int index = findInterval(intervals, transactionId);
boolean addedToExisting = false;
if (index < intervals.size()) {
Interval interval = intervals.get(index);
if (interval.start == transactionId + 1) {
interval.start = transactionId;
addedToExisting = true;
} else if (interval.end + 1 == transactionId) {
interval.end = transactionId;
addedToExisting = true;
} else if (interval.start <= transactionId && transactionId <= interval.end) {
return false;
}
}
if (!addedToExisting) {
intervals.add(index, new Interval(transactionId, transactionId));
}
if (intervals.size() > 1) {
joinAdjacentIntervals(intervals, index);
}
return true;
}
/**
* Collapses intervals like a-(b-1):b-c into a-c (only in index+-1 range).
*/
private void joinAdjacentIntervals(List intervals, int index) {
for (int i = Math.min(index + 1, intervals.size() - 1), e = Math.max(index - 1, 0); i > e; i--) {
Interval a = intervals.get(i - 1), b = intervals.get(i);
if (a.end + 1 == b.start) {
a.end = b.end;
intervals.remove(i);
}
}
}
@Override
public String toString() {
List gtids = new ArrayList();
for (UUIDSet uuidSet : map.values()) {
gtids.add(uuidSet.getUUID() + ":" + join(uuidSet.intervals, ":"));
}
return join(gtids, ",");
}
/**
* @return index which is either a pointer to the interval containing v or a
* position at which v can be added
*/
private static int findInterval(List ii, long v) {
int l = 0, p = 0, r = ii.size();
while (l < r) {
p = (l + r) / 2;
Interval i = ii.get(p);
if (i.end < v) {
l = p + 1;
} else if (v < i.start) {
r = p;
} else {
return p;
}
}
if (!ii.isEmpty() && ii.get(p).end < v) {
p++;
}
return p;
}
private String join(Collection o, String delimiter) {
if (o.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
for (Object o1 : o) {
sb.append(o1).append(delimiter);
}
return sb.substring(0, sb.length() - delimiter.length());
}
/**
* @see GtidSet
*/
public static final class UUIDSet {
private String uuid;
private Collection intervals;
private UUIDSet(String uuid, Collection intervals) {
this.uuid = uuid;
this.intervals = intervals;
}
public String getUUID() {
return uuid;
}
public Collection getIntervals() {
return intervals;
}
}
/**
* @see GtidSet
*/
public static final class Interval implements Comparable {
private long start;
private long end;
private Interval(long start, long end) {
this.start = start;
this.end = end;
}
public long getStart() {
return start;
}
public long getEnd() {
return end;
}
@Override
public String toString() {
return start + "-" + end;
}
@Override
public int compareTo(Interval o) {
return saturatedCast(this.start - o.start);
}
private static int saturatedCast(long value) {
if (value > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
if (value < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) value;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy