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

com.moilioncircle.redis.replicator.util.Lzf 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
/*
 * Copyright 2009-2010 Ning, Inc.
 *
 * 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.util;

/**
 * @author Ning
 * @author Leon Chen
 * @see VanillaChunkDecoder.java
 * @see VanillaChunkEncoder.java
 * @since 2.1.0
 */
public class Lzf {
    
    private static final int MAX_OFF = 1 << 13;
    private static final int HASH_SIZE = 1 << 14;
    private static final int MAX_LITERAL = 1 << 5;
    private static final int MAX_REF = (1 << 8) + (1 << 3);
    private static final ThreadLocal BUFFER = ThreadLocal.withInitial(() -> new long[HASH_SIZE]);
    
    public static ByteArray decode(ByteArray bytes, long len) {
        ByteArray out = new ByteArray(len);
        decode(bytes, 0, out, 0, len);
        return out;
    }
    
    private static void decode(ByteArray in, long inPos, ByteArray out, long outPos, long outEnd) {
        do {
            int ctrl = in.get(inPos++) & 255;
            if (ctrl < 1 << 5) {
                switch (ctrl) {
                    case 31:
                        out.set(outPos++, in.get(inPos++));
                    case 30:
                        out.set(outPos++, in.get(inPos++));
                    case 29:
                        out.set(outPos++, in.get(inPos++));
                    case 28:
                        out.set(outPos++, in.get(inPos++));
                    case 27:
                        out.set(outPos++, in.get(inPos++));
                    case 26:
                        out.set(outPos++, in.get(inPos++));
                    case 25:
                        out.set(outPos++, in.get(inPos++));
                    case 24:
                        out.set(outPos++, in.get(inPos++));
                    case 23:
                        out.set(outPos++, in.get(inPos++));
                    case 22:
                        out.set(outPos++, in.get(inPos++));
                    case 21:
                        out.set(outPos++, in.get(inPos++));
                    case 20:
                        out.set(outPos++, in.get(inPos++));
                    case 19:
                        out.set(outPos++, in.get(inPos++));
                    case 18:
                        out.set(outPos++, in.get(inPos++));
                    case 17:
                        out.set(outPos++, in.get(inPos++));
                    case 16:
                        out.set(outPos++, in.get(inPos++));
                    case 15:
                        out.set(outPos++, in.get(inPos++));
                    case 14:
                        out.set(outPos++, in.get(inPos++));
                    case 13:
                        out.set(outPos++, in.get(inPos++));
                    case 12:
                        out.set(outPos++, in.get(inPos++));
                    case 11:
                        out.set(outPos++, in.get(inPos++));
                    case 10:
                        out.set(outPos++, in.get(inPos++));
                    case 9:
                        out.set(outPos++, in.get(inPos++));
                    case 8:
                        out.set(outPos++, in.get(inPos++));
                    case 7:
                        out.set(outPos++, in.get(inPos++));
                    case 6:
                        out.set(outPos++, in.get(inPos++));
                    case 5:
                        out.set(outPos++, in.get(inPos++));
                    case 4:
                        out.set(outPos++, in.get(inPos++));
                    case 3:
                        out.set(outPos++, in.get(inPos++));
                    case 2:
                        out.set(outPos++, in.get(inPos++));
                    case 1:
                        out.set(outPos++, in.get(inPos++));
                    case 0:
                        out.set(outPos++, in.get(inPos++));
                }
                continue;
            }
            
            long len = ctrl >> 5;
            ctrl = -((ctrl & 0x1F) << 8) - 1;
            if (len < 7) {
                ctrl -= in.get(inPos++) & 255;
                out.set(outPos, out.get(outPos++ + ctrl));
                out.set(outPos, out.get(outPos++ + ctrl));
                switch ((int) len) {
                    case 6:
                        out.set(outPos, out.get(outPos++ + ctrl));
                    case 5:
                        out.set(outPos, out.get(outPos++ + ctrl));
                    case 4:
                        out.set(outPos, out.get(outPos++ + ctrl));
                    case 3:
                        out.set(outPos, out.get(outPos++ + ctrl));
                    case 2:
                        out.set(outPos, out.get(outPos++ + ctrl));
                    case 1:
                        out.set(outPos, out.get(outPos++ + ctrl));
                }
                continue;
            }
            
            len = in.get(inPos++) & 255;
            ctrl -= in.get(inPos++) & 255;
            
            if ((ctrl + len) < -9) {
                len += 9;
                if (len <= 32) {
                    long inPos1 = outPos + ctrl;
                    long outPos1 = outPos;
                    switch ((int) len - 1) {
                        case 31:
                            out.set(outPos1++, out.get(inPos1++));
                        case 30:
                            out.set(outPos1++, out.get(inPos1++));
                        case 29:
                            out.set(outPos1++, out.get(inPos1++));
                        case 28:
                            out.set(outPos1++, out.get(inPos1++));
                        case 27:
                            out.set(outPos1++, out.get(inPos1++));
                        case 26:
                            out.set(outPos1++, out.get(inPos1++));
                        case 25:
                            out.set(outPos1++, out.get(inPos1++));
                        case 24:
                            out.set(outPos1++, out.get(inPos1++));
                        case 23:
                            out.set(outPos1++, out.get(inPos1++));
                        case 22:
                            out.set(outPos1++, out.get(inPos1++));
                        case 21:
                            out.set(outPos1++, out.get(inPos1++));
                        case 20:
                            out.set(outPos1++, out.get(inPos1++));
                        case 19:
                            out.set(outPos1++, out.get(inPos1++));
                        case 18:
                            out.set(outPos1++, out.get(inPos1++));
                        case 17:
                            out.set(outPos1++, out.get(inPos1++));
                        case 16:
                            out.set(outPos1++, out.get(inPos1++));
                        case 15:
                            out.set(outPos1++, out.get(inPos1++));
                        case 14:
                            out.set(outPos1++, out.get(inPos1++));
                        case 13:
                            out.set(outPos1++, out.get(inPos1++));
                        case 12:
                            out.set(outPos1++, out.get(inPos1++));
                        case 11:
                            out.set(outPos1++, out.get(inPos1++));
                        case 10:
                            out.set(outPos1++, out.get(inPos1++));
                        case 9:
                            out.set(outPos1++, out.get(inPos1++));
                        case 8:
                            out.set(outPos1++, out.get(inPos1++));
                        case 7:
                            out.set(outPos1++, out.get(inPos1++));
                        case 6:
                            out.set(outPos1++, out.get(inPos1++));
                        case 5:
                            out.set(outPos1++, out.get(inPos1++));
                        case 4:
                            out.set(outPos1++, out.get(inPos1++));
                        case 3:
                            out.set(outPos1++, out.get(inPos1++));
                        case 2:
                            out.set(outPos1++, out.get(inPos1++));
                        case 1:
                            out.set(outPos1++, out.get(inPos1++));
                        case 0:
                            out.set(outPos1++, out.get(inPos1++));
                    }
                } else {
                    ByteArray.arraycopy(out, outPos + ctrl, out, outPos, len);
                }
                outPos += len;
                continue;
            }
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            out.set(outPos, out.get(outPos++ + ctrl));
            
            len += outPos;
            final long end = len - 3;
            while (outPos < end) {
                out.set(outPos, out.get(outPos++ + ctrl));
                out.set(outPos, out.get(outPos++ + ctrl));
                out.set(outPos, out.get(outPos++ + ctrl));
                out.set(outPos, out.get(outPos++ + ctrl));
            }
            if (len - outPos == 3) {
                out.set(outPos, out.get(outPos++ + ctrl));
                out.set(outPos, out.get(outPos++ + ctrl));
                out.set(outPos, out.get(outPos++ + ctrl));
            } else if (len - outPos == 2) {
                out.set(outPos, out.get(outPos++ + ctrl));
                out.set(outPos, out.get(outPos++ + ctrl));
            } else if (len - outPos == 1) {
                out.set(outPos, out.get(outPos++ + ctrl));
            }
        } while (outPos < outEnd);
        
        if (outPos != outEnd) {
            throw new AssertionError("corrupt data: overrun in decompress, input offset " + inPos + ", output offset " + outPos);
        }
    }
    
    public static ByteArray encode(ByteArray bytes) {
        long len = bytes.length();
        ByteArray out = new ByteArray(len - 4);
        len = encode(bytes, len, out, 0);
        if (len <= 0) {
            return bytes;
        } else {
            ByteArray r = new ByteArray(len);
            ByteArray.arraycopy(out, 0, r, 0, len);
            return r;
        }
    }
    
    public static long encode(ByteArray in, long inLen, ByteArray out, long outPos) {
        int inPos = 0;
        long[] hashTab = BUFFER.get();
        java.util.Arrays.fill(hashTab, 0);
        int literals = 0;
        outPos++;
        int future = first(in, 0);
        while (inPos < inLen - 4) {
            byte p2 = in.get(inPos + 2);
            // next
            future = (future << 8) + (p2 & 255);
            int off = hash(future);
            long ref = hashTab[off];
            hashTab[off] = inPos;
            // if (ref < inPos
            //       && ref > 0
            //       && (off = inPos - ref - 1) < MAX_OFF
            //       && in[ref + 2] == p2
            //       && (((in[ref] & 255) << 8) | (in[ref + 1] & 255)) ==
            //           ((future >> 8) & 0xffff)) {
            if (ref < inPos
                    && ref > 0
                    && (off = (int)(inPos - ref - 1)) < MAX_OFF
                    && in.get(ref + 2) == p2
                    && in.get(ref + 1) == (byte) (future >> 8)
                    && in.get(ref) == (byte) (future >> 16)) {
                // match
                long maxLen = inLen - inPos - 2;
                if (maxLen > MAX_REF) {
                    maxLen = MAX_REF;
                }
                if (outPos + 3 + 1 >= out.length()) {
                    int c = literals == 0 ? 1 : 0;
                    if (outPos - c + 3 + 1 >= out.length())
                        return 0;
                }
                if (literals == 0) {
                    // multiple back-references,
                    // so there is no literal run control byte
                    outPos--;
                } else {
                    // set the control byte at the start of the literal run
                    // to store the number of literals
                    out.set(outPos - literals - 1, (byte) (literals - 1));
                    literals = 0;
                }
                int len = 3;
                while (len < maxLen && in.get(ref + len) == in.get(inPos + len)) {
                    len++;
                }
                len -= 2;
                if (len < 7) {
                    out.set(outPos++, (byte) ((off >> 8) + (len << 5)));
                } else {
                    out.set(outPos++, (byte) ((off >> 8) + (7 << 5)));
                    out.set(outPos++, (byte) (len - 7));
                }
                out.set(outPos++, (byte) off);
                // move one byte forward to allow for a literal run control byte
                outPos++;
                inPos += len;
                // rebuild the future, and store the last bytes to the hashtable.
                // Storing hashes of the last bytes in back-reference improves
                // the compression ratio and only reduces speed slightly.
                future = first(in, inPos);
                future = next(future, in, inPos);
                hashTab[hash(future)] = inPos++;
                future = next(future, in, inPos);
                hashTab[hash(future)] = inPos++;
            } else {
                // copy one byte from input to output as part of literal
                if (outPos >= out.length()) {
                    return 0;
                }
                out.set(outPos++, in.get(inPos++));
                literals++;
                // at the end of this literal chunk, write the length
                // to the control byte and start a new chunk
                if (literals == MAX_LITERAL) {
                    out.set(outPos - literals - 1, (byte) (literals - 1));
                    literals = 0;
                    // move ahead one byte to allow for the
                    // literal run control byte
                    outPos++;
                }
            }
        }
        
        if (outPos + 3 > out.length()) {
            return 0;
        }
        
        // write the remaining few bytes as literals
        while (inPos < inLen) {
            out.set(outPos++, in.get(inPos++));
            literals++;
            if (literals == MAX_LITERAL) {
                out.set(outPos - literals - 1, (byte) (literals - 1));
                literals = 0;
                outPos++;
            }
        }
        // writes the final literal run length to the control byte
        out.set(outPos - literals - 1, (byte) (literals - 1));
        if (literals == 0) {
            outPos--;
        }
        return outPos;
    }
    
    private static int first(ByteArray in, long inPos) {
        return (in.get(inPos) << 8) | (in.get(inPos + 1) & 255);
    }
    
    private static int next(int v, ByteArray in, long inPos) {
        return (v << 8) | (in.get(inPos + 2) & 255);
    }
    
    private static int hash(int h) {
        return ((h * 2777) >> 9) & (HASH_SIZE - 1);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy