/**
* Constructs a VectorTimestamp with the provided clock and host.
*
* @classdesc
*
* A VectorTimestamp is a timestamp used according to the
* {@link http://en.wikipedia.org/wiki/Vector_clock Vector Clock Algorithm} It
* is so named because it contains a vector of numerical clock values for
* different hosts. VectorTimestamps are immutable.
*
* @see {@link http://en.wikipedia.org/wiki/Vector_clock Wikipedian explanation of the Vector Clock algorithm}
* @constructor
* @param {Object<String, Number>} clock The vector clock with host names
* corresponding to timestamps for host
* @param {String} host The host the timestamp belongs to
* @throws {String} An error string if the vector clock does not contain an
* entry for the host
*/
function VectorTimestamp(clock, host) {
/** @private */
this.clock = Util.objectShallowCopy(clock);
/** @private */
this.host = host;
/** @private */
this.ownTime = clock[this.host];
if (!clock.hasOwnProperty(host)) {
var exp = new Exception("Local host \"" + host + "\" is missing from timestamp:");
throw exp;
}
for (var host in this.clock) {
if (this.clock[host] == 0) {
delete this.clock[host];
}
}
}
/**
* Returns the host name of the host this vector timestamp belongs to
*
* @returns {String} The host name
*/
VectorTimestamp.prototype.getOwnHost = function() {
return this.host;
};
/**
* Returns the clock value of the host
*
* @returns {Number} The clock value
*/
VectorTimestamp.prototype.getOwnTime = function() {
return this.ownTime;
};
/**
* Returns the entire vector clock as a JSON object
*
* @returns {Object} the clock
*/
VectorTimestamp.prototype.getClock = function() {
var clock = {};
for(var key in this.clock) {
clock[key] = this.clock[key];
}
return clock;
};
/**
* <p>
* Returns a vector timestamp that is this updated with the argument. The
* timestamp updating is done according to the
* {@link http://en.wikipedia.org/wiki/Vector_clock Vector Clock algorithm}.
* That is, for each key in the set of all keys, newVT.clock[key] =
* max(this.clock[key], other.clock[key]). The host of the returned timestamp is
* the same as the host of this.
* </p>
*
* <p>
* Note that the returned timestamp is the updated timestamp. Neither this nor
* the argument timestamp is modified in any way, as VectorTimestamps are
* immutable
* </p>
*
* @see {@link http://en.wikipedia.org/wiki/Vector_clock Wikipedian explanation of the Vector Clock algorithm}
* @param {VectorTimestamp} other The other timestamp used to update the current
* one
* @returns {VectorTimestamp} The updated vector timestamp.
*/
VectorTimestamp.prototype.update = function(other) {
var clock = {};
for (var key in this.clock) {
clock[key] = this.clock[key];
}
for (var key in other.clock) {
if (!clock.hasOwnProperty(key)) {
clock[key] = other.clock[key];
}
clock[key] = Math.max(clock[key], other.clock[key]);
}
return new VectorTimestamp(clock, this.host);
};
/**
* <p>
* Gets the vector timestamp that is identical to this current one, except its
* own hosts clock has been incremented by one.
* </p>
*
* <p>
* Note that this method does not modify this, as VectorTimestamps are
* immutable.
* </p>
*
* @returns {VectorTimestamp} A vector timestamp identical to this, except with
* its own host's clock incremented by one
*/
VectorTimestamp.prototype.increment = function() {
var clock = {};
for (var key in this.clock) {
clock[key] = this.clock[key];
}
clock[this.host]++;
return new VectorTimestamp(clock, this.host);
};
/**
* <p>
* Checks if this VectorTimestamp is equal to another. Two vector timestamps are
* considered equal if they have they exact same host and the exact same
* key-value pairs.
* </p>
*
* @param {VectorTimestamp} other The other VectorTimestamp to compare against
* @returns {Boolean} True if this equals other
*/
VectorTimestamp.prototype.equals = function(other) {
for (var key in this.clock) {
if (this.clock[key] != other.clock[key]) {
return false;
}
}
for (var key in other.clock) {
if (other.clock[key] != this.clock[key]) {
return false;
}
}
return this.host == other.host;
};
/**
* <p>
* Compares two vector timestamp.
* </p>
*
* <p>
* Returns a negative number if this timestamp happens before other. Returns a
* positive number if other timestamp happens before this. Returns zero if both
* are concurrent or equal.
* </p>
*
* <p>
* Let x[host] be the logical clock value for host in vector clock x. A vector
* timestamp x is said to happen before y if for all hosts, x[host] <= y[host]
* AND there exists at least one host h such that x[h] < y[h]. x and y are said
* to be concurrent if x does not happen before y AND y does not happen before x
* </p>
*
* @param {VectorTimestamp} other the timestamp to compare to
* @returns {Number} the result of the comparison as defined above
*/
VectorTimestamp.prototype.compareTo = function(other) {
var thisFirst = false;
for (var host in this.clock) {
if (other.clock[host] != undefined && this.clock[host] < other.clock[host]) {
thisFirst = true;
break;
}
}
var otherFirst = false;
for (var host in other.clock) {
if (this.clock[host] != undefined && other.clock[host] < this.clock[host]) {
otherFirst = true;
break;
}
}
if (thisFirst && !otherFirst) {
return -1;
}
if (otherFirst && !thisFirst) {
return 1;
}
return 0;
};
/**
* <p>
* Compare two timestamps based on their local times only.
* </p>
*
* <p>
* Returns zero if this.host is not equal to other.host. Returns a negative
* number if this happens before other. Returns a positive number is other
* happens before this.
* </p>
*
* <p>
* A vector clock x is said to happen before y if they have the same host and
* x[host] < y[host]
* </p>
*
* @param {VectorTimestamp} other the timestamp to compare to
* @returns {Number} the result of the comparison as defined above
*/
VectorTimestamp.prototype.compareToLocal = function(other) {
if (this.host != other.host) {
return 0;
}
return this.clock[this.host] - other.clock[other.host];
};