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

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

/*
 * Copyright 2016-2017 Leon Chen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.moilioncircle.redis.replicator.rdb;

import static com.moilioncircle.redis.replicator.Constants.RDB_14BITLEN;
import static com.moilioncircle.redis.replicator.Constants.RDB_32BITLEN;
import static com.moilioncircle.redis.replicator.Constants.RDB_64BITLEN;
import static com.moilioncircle.redis.replicator.Constants.RDB_6BITLEN;
import static com.moilioncircle.redis.replicator.Constants.RDB_ENCVAL;
import static com.moilioncircle.redis.replicator.Constants.RDB_ENC_LZF;
import static java.lang.Double.doubleToLongBits;
import static java.lang.Float.floatToIntBits;
import static java.nio.ByteOrder.BIG_ENDIAN;
import static java.nio.ByteOrder.LITTLE_ENDIAN;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;

import com.moilioncircle.redis.replicator.util.ByteArray;
import com.moilioncircle.redis.replicator.util.Lzf;

/**
 * @author Leon Chen
 * @since 3.5.3
 */
public class BaseRdbEncoder {
    
    /**
     * @param time time
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadTime()
     * @since 3.5.3
     */
    public void rdbSaveTime(int time, OutputStream out) throws IOException {
        out.write(ByteBuffer.allocate(Integer.BYTES).order(LITTLE_ENDIAN).putInt(time).array());
    }
    
    /**
     * @since 3.5.3
     * @param timestamp timestamp
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadMillisecondTime()
     */
    public void rdbSaveMillisecondTime(long timestamp, OutputStream out) throws IOException {
        out.write(ByteBuffer.allocate(Long.BYTES).order(LITTLE_ENDIAN).putLong(timestamp).array());
    }
    
    /**
     * @since 3.5.3
     * @param len len
     * @param out out
     * @return length
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadLen()
     */
    public int rdbSaveLen(long len, OutputStream out) throws IOException {
        byte[] ary = toUnsigned(len);
        BigInteger value = new BigInteger(1, ary);
        if (value.compareTo(BigInteger.valueOf(0XFFFFFFFFL)) > 0) {
            /* Save a 64 bit len */
            out.write(RDB_64BITLEN);
            out.write(ByteBuffer.allocate(Long.BYTES).order(BIG_ENDIAN).put(ary).array());
            return 9;
        } else if (len < (1 << 6)) {
            out.write((byte) ((len & 0xFF) | (RDB_6BITLEN << 6)));
            return 1;
        } else if (len < (1 << 14)) {
            /* Save a 14 bit len */
            out.write((byte) (((len >> 8) & 0xFF) | (RDB_14BITLEN << 6)));
            out.write((byte) (len & 0xFF));
            return 2;
        } else if (len <= 0XFFFFFFFFL) {
            /* Save a 32 bit len */
            out.write(RDB_32BITLEN);
            out.write(ByteBuffer.allocate(Integer.BYTES).order(BIG_ENDIAN).putInt((int) len).array());
            return 5;
        } else {
            /* Save a 64 bit len */
            out.write(RDB_64BITLEN);
            out.write(ByteBuffer.allocate(Long.BYTES).order(BIG_ENDIAN).putLong(len).array());
            return 9;
        }
    }
    
    /**
     * @since 3.5.3
     * @param len len
     * @return byte array
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadLen()
     */
    public byte[] rdbSaveLen(long len) throws IOException {
        byte[] ary = toUnsigned(len);
        BigInteger value = new BigInteger(1, ary);
        if (value.compareTo(BigInteger.valueOf(0XFFFFFFFFL)) > 0) {
            /* Save a 64 bit len */
            return ByteBuffer.allocate(9).order(BIG_ENDIAN).put((byte) RDB_64BITLEN).put(ary).array();
        } else if (len < (1 << 6)) {
            return new byte[]{(byte) ((len & 0xFF) | (RDB_6BITLEN << 6))};
        } else if (len < (1 << 14)) {
            /* Save a 14 bit len */
            return new byte[]{(byte) (((len >> 8) & 0xFF) | (RDB_14BITLEN << 6)), (byte) (len & 0xFF)};
        } else if (len <= 0XFFFFFFFFL) {
            /* Save a 32 bit len */
            return ByteBuffer.allocate(5).order(BIG_ENDIAN).put((byte) RDB_32BITLEN).putInt((int) len).array();
        } else {
            /* Save a 64 bit len */
            return ByteBuffer.allocate(9).order(BIG_ENDIAN).put((byte) RDB_64BITLEN).putLong(len).array();
        }
    }
    
    public static void main(String[] args) {
        System.out.println(((int)0xffffffffL) & 0xffffffffL);
    }
    
    /**
     * @since 3.5.3
     * @param value value
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadDoubleValue()
     */
    public void rdbSaveDoubleValue(double value, OutputStream out) throws IOException {
        if (value == Double.NEGATIVE_INFINITY) {
            out.write(255);
        } else if (value == Double.POSITIVE_INFINITY) {
            out.write(254);
        } else if (Double.isNaN(value)) {
            out.write(253);
        } else {
            String str = null;
            if (value == (double) (long) value) {
                str = Long.toString((long) value, 10);
            } else {
                str = String.format("%.17f", value);
            }
            out.write(str.length());
            out.write(str.getBytes());
        }
    }
    
    /**
     * @since 3.5.3
     * @param value value
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadBinaryFloatValue()
     */
    public void rdbSaveBinaryFloatValue(float value, OutputStream out) throws IOException {
        out.write(ByteBuffer.allocate(Long.BYTES).order(LITTLE_ENDIAN).putLong(floatToIntBits(value)).array());
    }
    
    /**
     * @since 3.5.3
     * @param value value
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadBinaryDoubleValue()
     */
    public void rdbSaveBinaryDoubleValue(double value, OutputStream out) throws IOException {
        out.write(ByteBuffer.allocate(Long.BYTES).order(LITTLE_ENDIAN).putLong(doubleToLongBits(value)).array());
    }
    
    /**
     * @since 3.5.3
     * @param bytes input
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadEncodedStringObject()
     */
    public void rdbSaveEncodedStringObject(ByteArray bytes, OutputStream out) throws IOException {
        // at least compress 4 bytes
        ByteArray compressed = new ByteArray(bytes.length() - 4);
        long length = Lzf.encode(bytes, bytes.length(), compressed, 0);
        if (length <= 0) {
            rdbSavePlainStringObject(bytes, out);
        } else {
            int type = (RDB_ENCVAL << 6) | RDB_ENC_LZF;
            out.write(type);
            rdbSaveLen(length, out);
            rdbSaveLen(bytes.length(), out);
            out.write(compressed.first(), 0, (int) length);
        }
    }
    
    /**
     * @since 3.5.3
     * @param bytes bytes
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbGenericLoadStringObject(int)
     */
    public void rdbGenericSaveStringObject(ByteArray bytes, OutputStream out) throws IOException {
        if (bytes.length() > 20) {
            rdbSaveEncodedStringObject(bytes, out);
        } else {
            rdbSavePlainStringObject(bytes, out);
        }
    }
    
    /**
     * @since 3.5.3
     * @param bytes bytes
     * @param out out
     * @throws IOException IOException
     * @see BaseRdbParser#rdbLoadPlainStringObject()
     */
    public void rdbSavePlainStringObject(ByteArray bytes, OutputStream out) throws IOException {
        rdbSaveLen(bytes.length(), out);
        out.write(bytes.first());
    }
    
    private byte[] toUnsigned(long value) {
        byte[] ary = new byte[8];
        for (int i = 0; i < 8; i++) {
            ary[7 - i] = (byte) ((value >>> (i << 3)) & 0xFF);
        }
        return ary;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy