All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.microsoft.azure.documentdb.internal.VectorSessionToken Maven / Gradle / Ivy
package com.microsoft.azure.documentdb.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.microsoft.azure.documentdb.DocumentClientException;
public class VectorSessionToken {
private final static Logger logger = LoggerFactory.getLogger(VectorSessionToken.class);
private static final String SEGMENT_SEPARATOR = "#";
private static final String REGION_PROGRESS_SEPARATOR = "=";
private String sessionToken;
private long version;
private long globalLsn;
private Map localLsnByRegion;
public VectorSessionToken(long version, long globalLsn, Map localLsnByRegion) {
this(version, globalLsn, localLsnByRegion, null);
}
public VectorSessionToken(long version, long globalLsn, Map localLsnByRegion, String sessionToken) {
this.version = version;
this.globalLsn = globalLsn;
this.localLsnByRegion = localLsnByRegion;
this.sessionToken = sessionToken;
if (this.sessionToken == null) {
List regionAndLocalLsn = new ArrayList();
for (Entry kvp : localLsnByRegion.entrySet()) {
regionAndLocalLsn.add(kvp.getKey() + REGION_PROGRESS_SEPARATOR + kvp.getValue());
}
String regionProgress = String.join(SEGMENT_SEPARATOR, regionAndLocalLsn);
if (StringUtils.isEmpty(regionProgress)) {
this.sessionToken = String.format("%s%s%s",
this.version,
SEGMENT_SEPARATOR,
this.globalLsn);
} else {
this.sessionToken = String.format(
"%s%s%s%s%s",
this.version,
SEGMENT_SEPARATOR,
this.globalLsn,
SEGMENT_SEPARATOR,
regionProgress);
}
}
}
public static VectorSessionToken create(String sessionToken) {
Long version = null;
Long globalLsn = null;
if (StringUtils.isEmpty(sessionToken)) {
logger.trace("Session token is empty");
return null;
}
String[] segments = sessionToken.split(SEGMENT_SEPARATOR);
if (segments.length < 2) {
return null;
}
try {
version = Long.parseLong(segments[0]);
} catch (NumberFormatException e) {
logger.trace("Unexpected session token version number '{}'", segments[0]);
return null;
}
try {
globalLsn = Long.parseLong(segments[1]);
} catch (NumberFormatException e) {
logger.trace("Unexpected global lsn '{}'", segments[1]);
return null;
}
Map lsnByRegion = new HashMap();
for (int i = 2; i < segments.length; i++) {
String regionSegment = segments[i];
String[] regionIdWithLsn = regionSegment.split(REGION_PROGRESS_SEPARATOR);
if(regionIdWithLsn.length != 2) {
logger.trace("Unexpected region progress segment length '{}' in session token.", regionIdWithLsn.length);
return null;
}
Integer regionId = null;
Long localLsn = null;
try {
regionId = Integer.parseInt(regionIdWithLsn[0]);
localLsn = Long.parseLong(regionIdWithLsn[1]);
} catch (NumberFormatException e) {
logger.trace("Unexpected region progress '{}' for region '{}' in session token.", regionIdWithLsn[0], regionIdWithLsn[1]);
return null;
}
lsnByRegion.put(regionId, localLsn);
}
return new VectorSessionToken(version, globalLsn, lsnByRegion, sessionToken);
}
public boolean equals(VectorSessionToken other) {
return other == null ? false
: this.version == other.version && this.globalLsn == other.globalLsn
&& this.areRegionProgressEqual(other.localLsnByRegion);
}
public boolean isValid(VectorSessionToken other) throws DocumentClientException {
if (other == null) {
throw new IllegalArgumentException("Invalid Session Token (should not be null).");
}
if (other.version < this.version || other.globalLsn < this.globalLsn) {
return false;
}
if (other.version == this.version && other.localLsnByRegion.size() != this.localLsnByRegion.size()) {
throw new DocumentClientException(HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR,
String.format("Compared session tokens '{}' and '{}' has unexpected regions.",
this.sessionToken, other.sessionToken));
}
for (Entry kvp : other.localLsnByRegion.entrySet()) {
Integer regionId = kvp.getKey();
long otherLocalLsn = kvp.getValue();
Long localLsn = this.localLsnByRegion.get(regionId);
if (localLsn == null) {
// Region mismatch: other session token has progress for a region which is missing in this session token
// Region mismatch can be ignored only if this session token version is smaller than other session token version
if (this.version == other.version) {
throw new DocumentClientException(HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR,
String.format("Compared session tokens '{}' and '{}' has unexpected regions.",
this.sessionToken, other.sessionToken));
}
else {
// ignore missing region as other session token version > this session token version
}
}
else {
// region is present in both session tokens.
if (otherLocalLsn < localLsn) {
return false;
}
}
}
return true;
}
public VectorSessionToken merge(VectorSessionToken other) throws DocumentClientException {
if (other == null) {
throw new IllegalArgumentException("Invalid Session Token (should not be null).");
}
if (this.version == other.version && this.localLsnByRegion.size() != other.localLsnByRegion.size()) {
throw new DocumentClientException(HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR,
String.format("Compared session tokens '{}' and '{}' has unexpected regions.",
this.sessionToken, other.sessionToken));
}
VectorSessionToken sessionTokenWithHigherVersion;
VectorSessionToken sessionTokenWithLowerVersion;
if (this.version < other.version) {
sessionTokenWithLowerVersion = this;
sessionTokenWithHigherVersion = other;
} else {
sessionTokenWithLowerVersion = other;
sessionTokenWithHigherVersion = this;
}
Map highestLocalLsnByRegion = new HashMap();
for (Entry kvp : sessionTokenWithHigherVersion.localLsnByRegion.entrySet()) {
int regionId = kvp.getKey();
long localLsn1 = kvp.getValue();
Long localLsn2 = sessionTokenWithLowerVersion.localLsnByRegion.get(regionId);
if (localLsn2 != null) {
highestLocalLsnByRegion.put(regionId, Math.max(localLsn1, localLsn2));
} else if (this.version == other.version) {
throw new DocumentClientException(HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR,
String.format("Compared session tokens '{}' and '{}' has unexpected regions.",
this.sessionToken, other.sessionToken));
} else {
highestLocalLsnByRegion.put(regionId, localLsn1);
}
}
return new VectorSessionToken(
Math.max(this.version, other.version),
Math.max(this.globalLsn, other.globalLsn),
highestLocalLsnByRegion);
}
public String convertToString() {
return this.sessionToken;
}
private boolean areRegionProgressEqual(Map other) {
if (this.localLsnByRegion.size() != other.size()) {
return false;
}
for (Entry kvp : this.localLsnByRegion.entrySet()) {
int regionId = kvp.getKey();
long localLsn1 = kvp.getValue();
Long localLsn2 = other.get(regionId);
if (localLsn2 != null) {
if (localLsn1 != localLsn2) {
return false;
}
}
}
return true;
}
}