All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.river.mongodb.Timestamp Maven / Gradle / Ivy

The newest version!
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;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy