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

com.moilioncircle.redis.replicator.rdb.Rdb7Parser Maven / Gradle / Ivy

Go to download

Redis Replicator implement Redis Replication protocol written in java. It can parse,filter,broadcast the RDB and AOF events in a real time manner. It also can synchronize redis data to your local cache or to database.

There is a newer version: 3.8.1
Show newest version
package com.moilioncircle.redis.replicator.rdb;

import com.moilioncircle.redis.replicator.AbstractReplicator;
import com.moilioncircle.redis.replicator.io.RedisInputStream;
import com.moilioncircle.redis.replicator.rdb.datatype.*;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;

import static com.moilioncircle.redis.replicator.Constants.*;

/**
 * Created by leon on 8/20/16.
 */
public class Rdb7Parser extends AbstractRdbParser {

    public Rdb7Parser(RedisInputStream in, AbstractReplicator replicator) {
        super(in, replicator);
    }

    protected long rdbLoad() throws IOException, InterruptedException {
        Db db = null;
        /**
         * rdb
         */
        loop:
        while (true) {
            int type = in.read();
            KeyValuePair kv = null;
            switch (type) {
                /*
                 * ----------------------------
                 * FD $unsigned int            # FD indicates "expiry time in seconds". After that, expiry time is read as a 4 byte unsigned int
                 * $value-type                 # 1 byte flag indicating the type of value - set, map, sorted set etc.
                 * $string-encoded-name         # The name, encoded as a redis string
                 * $encoded-value              # The value. Encoding depends on $value-type
                 * ----------------------------
                 */
                case REDIS_RDB_OPCODE_EXPIRETIME:
                    int expiredSec = rdbLoadTime();
                    int valueType = in.read();
                    String key = rdbLoadEncodedStringObject();
                    kv = rdbLoadObject(valueType);
                    kv.setDb(db);
                    kv.setExpiredSeconds(expiredSec);
                    kv.setKey(key);
                    break;
                /*
                 * ----------------------------
                 * FC $unsigned long           # FC indicates "expiry time in ms". After that, expiry time is read as a 8 byte unsigned long
                 * $value-type                 # 1 byte flag indicating the type of value - set, map, sorted set etc.
                 * $string-encoded-name         # The name, encoded as a redis string
                 * $encoded-value              # The value. Encoding depends on $value-type
                 * ----------------------------
                 */
                case REDIS_RDB_OPCODE_EXPIRETIME_MS:
                    long expiredMs = rdbLoadMillisecondTime();
                    valueType = in.read();
                    key = rdbLoadEncodedStringObject();
                    kv = rdbLoadObject(valueType);
                    kv.setDb(db);
                    kv.setExpiredMs(expiredMs);
                    kv.setKey(key);
                    break;
                case REDIS_RDB_OPCODE_AUX:
                    String auxKey = rdbLoadEncodedStringObject();
                    String auxValue = rdbLoadEncodedStringObject();
                    if (auxKey.startsWith("%")) {
                        logger.info("RDB " + auxKey + ": " + auxValue);
                    } else {
                        logger.debug("Unrecognized RDB AUX field: " + auxKey + ",value: " + auxValue);
                    }
                    break;
                case REDIS_RDB_OPCODE_RESIZEDB:
                    int dbsize = rdbLoadLen().len;
                    int expiresSize = rdbLoadLen().len;
                    db.setDbsize(dbsize);
                    db.setExpires(expiresSize);
                    break;
                /*
                 * ----------------------------
                 * $value-type                 # This name value pair doesn't have an expiry. $value_type guaranteed != to FD, FC, FE and FF
                 * $string-encoded-name
                 * $encoded-value
                 * ----------------------------
                 */
                case REDIS_RDB_TYPE_STRING:
                case REDIS_RDB_TYPE_LIST:
                case REDIS_RDB_TYPE_SET:
                case REDIS_RDB_TYPE_ZSET:
                case REDIS_RDB_TYPE_HASH:
                case REDIS_RDB_TYPE_HASH_ZIPMAP:
                case REDIS_RDB_TYPE_LIST_ZIPLIST:
                case REDIS_RDB_TYPE_SET_INTSET:
                case REDIS_RDB_TYPE_ZSET_ZIPLIST:
                case REDIS_RDB_TYPE_HASH_ZIPLIST:
                case REDIS_RDB_TYPE_LIST_QUICKLIST:
                    valueType = type;
                    key = rdbLoadEncodedStringObject();
                    kv = rdbLoadObject(valueType);
                    kv.setDb(db);
                    kv.setKey(key);
                    break;
                /*
                 * ----------------------------
                 * FE $length-encoding         # Previous db ends, next db starts. Database number read using length encoding.
                 * ----------------------------
                 */
                case REDIS_RDB_OPCODE_SELECTDB:
                    int dbNumber = rdbLoadLen().len;
                    db = new Db(dbNumber);
                    break;
                /*
                 * ----------------------------
                 * ...                         # Key value pairs for this database, additonal database
                 * FF                          ## End of RDB file indicator
                 * 8 byte checksum             ## CRC 64 checksum of the entire file.
                 * ----------------------------
                 */
                case REDIS_RDB_OPCODE_EOF:
                    byte[] checksum = in.readBytes(8);
                    break loop;
                default:
                    throw new AssertionError("Un-except value-type:" + type);
            }
            if (kv == null) continue;
            if (replicator.verbose() && logger.isDebugEnabled()) logger.debug(kv);
            //submit event
            this.replicator.submitEvent(kv);
        }
        return in.total();
    }

    private KeyValuePair rdbLoadObject(int rdbtype) throws IOException {
        switch (rdbtype) {
            /*
             * |              |
             * |    string contents    |
             */
            case REDIS_RDB_TYPE_STRING:
                KeyStringValueString o0 = new KeyStringValueString();
                String val = rdbLoadEncodedStringObject();
                o0.setValueRdbType(rdbtype);
                o0.setValue(val);
                return o0;
            /*
             * |         |              |
             * | 1 or 5 bytes |    string contents    |
             */
            case REDIS_RDB_TYPE_LIST:
                int len = rdbLoadLen().len;
                KeyStringValueList o1 = new KeyStringValueList<>();
                List list = new ArrayList<>();
                for (int i = 0; i < len; i++) {
                    String element = rdbLoadEncodedStringObject();
                    list.add(element);
                }
                o1.setValueRdbType(rdbtype);
                o1.setValue(list);
                return o1;
            /*
             * |         |              |
             * | 1 or 5 bytes |    string contents    |
             */
            case REDIS_RDB_TYPE_SET:
                len = rdbLoadLen().len;
                KeyStringValueSet o2 = new KeyStringValueSet();
                Set set = new LinkedHashSet<>();
                for (int i = 0; i < len; i++) {
                    String element = rdbLoadEncodedStringObject();
                    set.add(element);
                }
                o2.setValueRdbType(rdbtype);
                o2.setValue(set);
                return o2;
            /*
             * |         |              |               |
             * | 1 or 5 bytes |    string contents    |    double content    |
             */
            case REDIS_RDB_TYPE_ZSET:
                len = rdbLoadLen().len;
                KeyStringValueZSet o3 = new KeyStringValueZSet();
                Set zset = new LinkedHashSet<>();
                while (len > 0) {
                    String element = rdbLoadEncodedStringObject();
                    double score = rdbLoadDoubleValue();
                    zset.add(new ZSetEntry(element, score));
                    len--;
                }
                o3.setValueRdbType(rdbtype);
                o3.setValue(zset);
                return o3;
            /*
             * |         |              |
             * | 1 or 5 bytes |    string contents    |
             */
            case REDIS_RDB_TYPE_HASH:
                len = rdbLoadLen().len;
                KeyStringValueHash o4 = new KeyStringValueHash();
                Map map = new LinkedHashMap<>();
                while (len > 0) {
                    String field = rdbLoadEncodedStringObject();
                    String value = rdbLoadEncodedStringObject();
                    map.put(field, value);
                    len--;
                }
                o4.setValueRdbType(rdbtype);
                o4.setValue(map);
                return o4;
            /*
             * | |        |"foo"    |       |  |   "bar" | |
             * | 1 byte | 1 or 5 byte | content |1 or 5 byte | 1 byte | content | 1 byte |
             */
            case REDIS_RDB_TYPE_HASH_ZIPMAP:
                byte[] aux = rdbLoadRawStringObject();
                RedisInputStream stream = new RedisInputStream(new ByteArrayInputStream(aux));
                KeyStringValueHash o9 = new KeyStringValueHash();
                map = new LinkedHashMap<>();
                int zmlen = AbstractRdbParser.LenHelper.zmlen(stream);
                while (true) {
                    int zmEleLen = AbstractRdbParser.LenHelper.zmElementLen(stream);
                    if (zmEleLen == -1) {
                        break;
                    }
                    String field = AbstractRdbParser.StringHelper.str(stream, zmEleLen);
                    zmEleLen = AbstractRdbParser.LenHelper.zmElementLen(stream);
                    int free = AbstractRdbParser.LenHelper.free(stream);
                    String value = AbstractRdbParser.StringHelper.str(stream, zmEleLen);
                    AbstractRdbParser.StringHelper.skip(stream, free);
                    map.put(field, value);
                }
                int zmend = AbstractRdbParser.LenHelper.zmend(stream);
                if (zmend != 255) {
                    throw new AssertionError("zmend expected 255 but " + zmend);
                }
                o9.setValueRdbType(rdbtype);
                o9.setValue(map);
                return o9;
            /*
             * || |                                         |
             * | 4 bytes  |            4 bytes  | 2 bytes lement| 4 bytes element | 8 bytes element |
             */
            case REDIS_RDB_TYPE_SET_INTSET:
                aux = rdbLoadRawStringObject();
                stream = new RedisInputStream(new ByteArrayInputStream(aux));
                KeyStringValueSet o11 = new KeyStringValueSet();
                set = new LinkedHashSet<>();
                int encoding = AbstractRdbParser.LenHelper.encoding(stream);
                int lenOfContent = AbstractRdbParser.LenHelper.lenOfContent(stream);
                for (int i = 0; i < lenOfContent; i++) {
                    switch (encoding) {
                        case 2:
                            set.add(String.valueOf(stream.readInt(2)));
                            break;
                        case 4:
                            set.add(String.valueOf(stream.readInt(4)));
                            break;
                        case 8:
                            set.add(String.valueOf(stream.readLong(8)));
                            break;
                        default:
                            throw new AssertionError("Expect encoding [2,4,8] but:" + encoding);
                    }
                }
                o11.setValueRdbType(rdbtype);
                o11.setValue(set);
                return o11;
            /*
             * || | |  ... | |
             * | 4 bytes | 4 bytes | 2bytes | zipListEntry ...   | 1byte  |
             */
            case REDIS_RDB_TYPE_LIST_ZIPLIST:
                aux = rdbLoadRawStringObject();
                stream = new RedisInputStream(new ByteArrayInputStream(aux));
                KeyStringValueList o10 = new KeyStringValueList<>();
                list = new ArrayList<>();
                int zlbytes = AbstractRdbParser.LenHelper.zlbytes(stream);
                int zltail = AbstractRdbParser.LenHelper.zltail(stream);
                int zllen = AbstractRdbParser.LenHelper.zllen(stream);
                for (int i = 0; i < zllen; i++) {
                    list.add(AbstractRdbParser.StringHelper.zipListEntry(stream));
                }
                int zlend = AbstractRdbParser.LenHelper.zlend(stream);
                if (zlend != 255) {
                    throw new AssertionError("zlend expected 255 but " + zlend);
                }
                o10.setValueRdbType(rdbtype);
                o10.setValue(list);
                return o10;
            /*
             * || | |  ... | |
             * | 4 bytes | 4 bytes | 2bytes | zipListEntry ...   | 1byte  |
             */
            case REDIS_RDB_TYPE_ZSET_ZIPLIST:
                aux = rdbLoadRawStringObject();
                stream = new RedisInputStream(new ByteArrayInputStream(aux));
                KeyStringValueZSet o12 = new KeyStringValueZSet();
                zset = new LinkedHashSet<>();
                zlbytes = AbstractRdbParser.LenHelper.zlbytes(stream);
                zltail = AbstractRdbParser.LenHelper.zltail(stream);
                zllen = AbstractRdbParser.LenHelper.zllen(stream);
                while (zllen > 0) {
                    String element = AbstractRdbParser.StringHelper.zipListEntry(stream);
                    zllen--;
                    double score = Double.valueOf(AbstractRdbParser.StringHelper.zipListEntry(stream));
                    zllen--;
                    zset.add(new ZSetEntry(element, score));
                }
                zlend = AbstractRdbParser.LenHelper.zlend(stream);
                if (zlend != 255) {
                    throw new AssertionError("zlend expected 255 but " + zlend);
                }
                o12.setValueRdbType(rdbtype);
                o12.setValue(zset);
                return o12;
            /*
             * || | |  ... | |
             * | 4 bytes | 4 bytes | 2bytes | zipListEntry ...   | 1byte  |
             */
            case REDIS_RDB_TYPE_HASH_ZIPLIST:
                aux = rdbLoadRawStringObject();
                stream = new RedisInputStream(new ByteArrayInputStream(aux));
                KeyStringValueHash o13 = new KeyStringValueHash();
                map = new LinkedHashMap<>();
                zlbytes = AbstractRdbParser.LenHelper.zlbytes(stream);
                zltail = AbstractRdbParser.LenHelper.zltail(stream);
                zllen = AbstractRdbParser.LenHelper.zllen(stream);
                while (zllen > 0) {
                    String field = AbstractRdbParser.StringHelper.zipListEntry(stream);
                    zllen--;
                    String value = AbstractRdbParser.StringHelper.zipListEntry(stream);
                    zllen--;
                    map.put(field, value);
                }
                zlend = AbstractRdbParser.LenHelper.zlend(stream);
                if (zlend != 255) {
                    throw new AssertionError("zlend expected 255 but " + zlend);
                }
                o13.setValueRdbType(rdbtype);
                o13.setValue(map);
                return o13;
            /* rdb version 7*/
            case REDIS_RDB_TYPE_LIST_QUICKLIST:
                len = rdbLoadLen().len;
                KeyStringValueList o14 = new KeyStringValueList<>();
                List byteList = new ArrayList<>();
                for (int i = 0; i < len; i++) {
                    byte[] element = rdbLoadRawStringObject();
                    byteList.add(element);
                }
                o14.setValueRdbType(rdbtype);
                o14.setValue(byteList);
                return o14;
            default:
                throw new AssertionError("Un-except value-type:" + rdbtype);

        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy