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

com.github.housepower.jdbc.buffer.CompressedBuffedWriter Maven / Gradle / Ivy

package com.github.housepower.jdbc.buffer;

import com.github.housepower.jdbc.misc.ClickHouseCityHash;

import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;

import java.io.IOException;

public class CompressedBuffedWriter implements BuffedWriter {

    private int position;
    private int capacity;

    private final byte[] writtenBuf;
    private final BuffedWriter writer;
    private final LZ4Compressor lz4Compressor = LZ4Factory.safeInstance().fastCompressor();

    public CompressedBuffedWriter(int capacity, BuffedWriter writer) {
        this.capacity = capacity;
        this.writtenBuf = new byte[capacity];
        this.writer = writer;
    }


    @Override
    public void writeBinary(byte byt) throws IOException {
        writtenBuf[position++] = byt;
        flushToTarget(false);
    }

    @Override
    public void writeBinary(byte[] bytes) throws IOException {
        writeBinary(bytes, 0, bytes.length);
    }

    @Override
    public void writeBinary(byte[] bytes, int offset, int length) throws IOException {
        while (remaing() < length) {
            int num = remaing();
            System.arraycopy(bytes, offset, writtenBuf, position, remaing());
            position += num;

            flushToTarget(false);
            offset += num;
            length -= num;
        }

        System.arraycopy(bytes, offset, writtenBuf, position, length);
        position += length;
        flushToTarget(false);
    }


    private static final int COMPRESSION_HEADER_LENGTH = 9;

    @Override
    public void flushToTarget(boolean force) throws IOException {
        if (position > 0 && (force || !hasRemaining())) {
            int maxLen = lz4Compressor.maxCompressedLength(position);

            byte[] compressedBuffer = new byte[maxLen + 9 + 16];
            int res = lz4Compressor.compress(writtenBuf, 0, position, compressedBuffer, 9 + 16);

            compressedBuffer[16] = (byte) (0x82 & 0xFF);
            int compressedSize = res + COMPRESSION_HEADER_LENGTH;
            System.arraycopy(littleEndian(compressedSize), 0, compressedBuffer, 17, 4);
            System.arraycopy(littleEndian(position), 0, compressedBuffer, 21, 4);

            long[] checksum = ClickHouseCityHash.cityHash128(compressedBuffer, 16, compressedSize);
            System.arraycopy(littleEndian(checksum[0]), 0, compressedBuffer, 0, 8);
            System.arraycopy(littleEndian(checksum[1]), 0, compressedBuffer, 8, 8);

            writer.writeBinary(compressedBuffer, 0, compressedSize + 16);
            position = 0;
        }
    }

    private boolean hasRemaining() {
        return position < capacity;
    }

    private int remaing() {
        return capacity - position;
    }

    private byte[] littleEndian(int x) {
        byte[] data = new byte[4];

        data[0] = (byte) (x & 0xFF);
        data[1] = (byte) ((byte) (x >> 8) & 0xFF);
        data[2] = (byte) ((byte) (x >> 16) & 0xFF);
        data[3] = (byte) ((byte) (x >> 24) & 0xFF);

        return data;
    }

    private byte[] littleEndian(long x) {
        byte[] data = new byte[8];

        data[0] = (byte) (x & 0xFF);
        data[1] = (byte) ((byte) (x >> 8) & 0xFF);
        data[2] = (byte) ((byte) (x >> 16) & 0xFF);
        data[3] = (byte) ((byte) (x >> 24) & 0xFF);
        data[4] = (byte) ((byte) (x >> 32) & 0xFF);
        data[5] = (byte) ((byte) (x >> 40) & 0xFF);
        data[6] = (byte) ((byte) (x >> 48) & 0xFF);
        data[7] = (byte) ((byte) (x >> 56) & 0xFF);

        return data;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy