org.elasticsearch.river.mongodb.Timestamp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch-river-mongodb Show documentation
Show all versions of elasticsearch-river-mongodb Show documentation
MongoDB River for ElasticSearch
package org.elasticsearch.river.mongodb;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import org.bson.types.BSONTimestamp;
import org.bson.types.Binary;
import org.elasticsearch.common.xcontent.XContentBuilder;
import com.google.common.primitives.UnsignedBytes;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.QueryOperators;
import com.mongodb.util.JSON;
import com.mongodb.util.JSONSerializers;
/**
* Wrapper for BSON datatypes used in different MongoDB distros to specify the order of ops in the oplog.
* In the official distro a {@link BSONTimestamp} is used.
* In the TokuMX distro, a GTID is encoded in BSON as a generic {@link Binary}.
*/
public abstract class Timestamp> implements Comparable> {
public abstract long getTime();
public final static class BSON extends Timestamp {
private final BSONTimestamp ts;
public BSON(BSONTimestamp ts) {
if (ts == null) {
throw new IllegalArgumentException("ts must not be null");
}
this.ts = ts;
}
@Override
public int compareTo(Timestamp o) {
return this.ts.compareTo(((BSON) o).ts);
}
@Override
public boolean equals(Object o) {
return o instanceof BSON && ts.equals(((BSON) o).ts);
}
@Override
public int hashCode() {
return ts.hashCode();
}
@Override
public String toString() {
return "Timestamp.BSON(ts=" + JSON.serialize(ts) + ")";
}
@Override
public long getTime() {
return ts.getTime() * 1000L;
}
@Override
public DBObject getOplogFilter() {
return new BasicDBObject(MongoDBRiver.OPLOG_TIMESTAMP, new BasicDBObject(QueryOperators.GTE, ts));
}
@Override
public void saveFields(XContentBuilder builder) throws IOException {
builder.field(MongoDBRiver.LAST_TIMESTAMP_FIELD, JSON.serialize(ts));
}
}
public final static class GTID extends Timestamp {
private final byte[] gtid;
private final Date ts;
public GTID(byte[] gtid, Date ts) {
if (gtid == null) {
throw new IllegalArgumentException("gtid must not be null");
}
if (gtid.length != 128 / 8) { // number of octets in 128 bits
throw new IllegalArgumentException("gtid must encode two unsigned longs (128 total bits in length)");
}
this.gtid = gtid;
this.ts = ts;
}
@Override
public int compareTo(Timestamp o) {
return UnsignedBytes.lexicographicalComparator().compare(this.gtid, ((GTID) o).gtid);
}
@Override
public boolean equals(Object o) {
return o instanceof GTID && Arrays.equals(gtid, ((GTID) o).gtid);
}
@Override
public int hashCode() {
return Arrays.hashCode(gtid);
}
@Override
public String toString() {
return "Timestamp.GTID(ts=" + JSON.serialize(ts) + ", gtid=" + JSONSerializers.getStrict().serialize(gtid) + ")";
}
@Override
public long getTime() {
return ts.getTime();
}
@Override
public DBObject getOplogFilter() {
return new BasicDBObject(MongoDBRiver.MONGODB_ID_FIELD, new BasicDBObject(QueryOperators.GTE, gtid));
}
@Override
public void saveFields(XContentBuilder builder) throws IOException {
builder.field(MongoDBRiver.LAST_TIMESTAMP_FIELD, JSON.serialize(ts));
builder.field(MongoDBRiver.LAST_GTID_FIELD, JSONSerializers.getStrict().serialize(gtid));
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static int compare(Timestamp oplogTimestamp, Timestamp startTimestamp) {
return oplogTimestamp.compareTo(startTimestamp);
}
/** Parse timestamp field(s) on an oplog entry. */
public static Timestamp> on(DBObject entry) {
return on(entry.toMap(), false);
}
/** Parse last timestamp field(s) from river source metadata. */
public static Timestamp> on(Map map) {
return on(map, true);
}
private static Timestamp> on(@SuppressWarnings("rawtypes") Map map, boolean meta) {
String tsField = meta ? MongoDBRiver.LAST_TIMESTAMP_FIELD : MongoDBRiver.OPLOG_TIMESTAMP;
Object timestamp = map.get(tsField);
if (timestamp == null) {
return null;
}
if (timestamp instanceof String) {
timestamp = JSON.parse((String) timestamp);
}
if (timestamp instanceof BSONTimestamp) {
BSON result = new Timestamp.BSON((BSONTimestamp) timestamp);
return result;
}
if (timestamp instanceof Date) {
String gtidField = meta ? MongoDBRiver.LAST_GTID_FIELD : MongoDBRiver.MONGODB_ID_FIELD;
Object id = map.get(gtidField);
GTID result = null;
if (id == null) {
throw new IllegalStateException("Missing property: " + gtidField);
}
if (id instanceof String) {
id = JSON.parse((String) id);
}
if (id instanceof Binary) {
result = new Timestamp.GTID(((Binary) id).getData(), (Date) timestamp);
} else if (id instanceof byte[]) {
result = new Timestamp.GTID((byte[]) id, (Date) timestamp);
}
if (result == null) {
throw new IllegalStateException("Unable to parse " + gtidField
+ " " + id + " of type " + id.getClass());
}
return result;
}
throw new IllegalStateException("Unable to parse " + tsField
+ " " + timestamp + " of type " + timestamp.getClass());
}
public abstract DBObject getOplogFilter();
public abstract void saveFields(XContentBuilder builder) throws IOException;
}