com.tesora.dve.db.mysql.libmy.MyBinaryResultRow.java Source code

Java tutorial

Introduction

Here is the source code for com.tesora.dve.db.mysql.libmy.MyBinaryResultRow.java

Source

package com.tesora.dve.db.mysql.libmy;

/*
 * #%L
 * Tesora Inc.
 * Database Virtualization Engine
 * %%
 * Copyright (C) 2011 - 2014 Tesora Inc.
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */

import com.tesora.dve.exceptions.PECodingException;
import com.tesora.dve.exceptions.PEException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

public class MyBinaryResultRow extends MyResponseMessage {
    static final Logger log = LoggerFactory.getLogger(MyBinaryResultRow.class);

    //TODO: need to figure out a way to reduce downstream need to collect rowset headers. introduce flags and allow autoinc modifications? -sgossard
    List<DecodedMeta> fieldConverters;
    List<ByteBuf> fieldSlices;

    public MyBinaryResultRow(List<DecodedMeta> fieldConverters) {
        this.fieldConverters = fieldConverters;
        this.fieldSlices = new ArrayList<ByteBuf>();
        for (int i = 0; i < fieldConverters.size(); i++) {
            this.fieldSlices.add(null);
        }
    }

    protected MyBinaryResultRow(List<DecodedMeta> fieldConverters, List<ByteBuf> fieldSlices) {
        this.fieldConverters = fieldConverters;
        this.fieldSlices = fieldSlices;
    }

    @Override
    public MyMessageType getMessageType() {
        throw new PECodingException(MyBinaryResultRow.class.getSimpleName());
    }

    public MyBinaryResultRow append(DecodedMeta valueFunc, Object value) {
        ByteBuf valueBuf = Unpooled.buffer().order(ByteOrder.LITTLE_ENDIAN);
        valueFunc.writeObject(valueBuf, value);
        return this.append(valueFunc, valueBuf);
    }

    public MyBinaryResultRow append(DecodedMeta valueFunc, ByteBuf fieldSlice) {
        List<DecodedMeta> copyOfFuncs = new ArrayList<>(this.fieldConverters);
        copyOfFuncs.add(valueFunc);

        List<ByteBuf> newFields = new ArrayList<>(this.fieldSlices);
        newFields.add(fieldSlice);

        return new MyBinaryResultRow(copyOfFuncs, newFields);
    }

    @Override
    public void marshallMessage(ByteBuf cb) {
        cb.writeZero(1);//binary row marker
        byte[] bitmapArray = constructNullMap();
        cb.writeBytes(bitmapArray);
        marshallRawValues(cb);
    }

    private byte[] constructNullMap() {
        MyNullBitmap constructBitMap = new MyNullBitmap(fieldSlices.size(), MyNullBitmap.BitmapType.RESULT_ROW);
        for (int i = 0; i < fieldSlices.size(); i++) {
            if (fieldSlices.get(i) == null)
                constructBitMap.setBit(i + 1);
        }
        return constructBitMap.getBitmapArray();
    }

    public void marshallRawValues(ByteBuf cb) {
        for (int i = 0; i < fieldSlices.size(); i++) {
            ByteBuf fieldSlice = fieldSlices.get(i);
            if (fieldSlice != null)
                cb.writeBytes(fieldSlice.slice());
        }
    }

    @Override
    public void unmarshallMessage(ByteBuf cb) throws PEException {
        int expectedFieldCount = fieldConverters.size();
        int expectedBitmapLength = MyNullBitmap.computeSize(expectedFieldCount, MyNullBitmap.BitmapType.RESULT_ROW);
        cb = cb.order(ByteOrder.LITTLE_ENDIAN);
        cb.skipBytes(1);//skip the bin row marker.

        byte[] nullBitmap = new byte[expectedBitmapLength];
        cb.readBytes(nullBitmap);
        MyNullBitmap resultBitmap = new MyNullBitmap(nullBitmap, expectedFieldCount,
                MyNullBitmap.BitmapType.RESULT_ROW);

        ByteBuf values = cb;

        for (int i = 0; i < expectedFieldCount; i++) {
            ByteBuf existing = fieldSlices.get(i);
            ByteBuf nextSlice = null;
            int startIndex = values.readerIndex();
            if (!resultBitmap.getBit(i + 1)) {
                fieldConverters.get(i).readObject(values);//TODO: we throw out the unmarshalled value, we could cache it.
                int endingOffset = values.readerIndex();
                nextSlice = values.slice(startIndex, endingOffset - startIndex);
            }

            if (existing != null)
                existing.release();
            fieldSlices.set(i, nextSlice);
        }
        if (cb.readableBytes() > 0) {
            log.warn("Decoded binary row had {} leftover bytes, re-encoding may fail.", cb.readableBytes());
            cb.skipBytes(cb.readableBytes());//consume rest of buffer.
        }
    }

    public MyBinaryResultRow projection(int[] desiredFields) {
        int expectedFieldCount = desiredFields.length;

        ArrayList<ByteBuf> newSlices = new ArrayList<>(expectedFieldCount);
        ArrayList<DecodedMeta> newConverters = new ArrayList<>(expectedFieldCount);

        for (int targetIndex = 0; targetIndex < expectedFieldCount; targetIndex++) {
            int sourceIndex = desiredFields[targetIndex];
            newConverters.add(fieldConverters.get(sourceIndex));//use the source index, not the target index..
            if (fieldSlices.get(sourceIndex) == null) {
                newSlices.add(null);
            } else {
                ByteBuf fieldSlice = fieldSlices.get(sourceIndex);
                ByteBuf copySlice = Unpooled.buffer(fieldSlice.readableBytes()).order(ByteOrder.LITTLE_ENDIAN);
                copySlice.writeBytes(fieldSlice.slice());
                newSlices.add(copySlice);
            }
        }

        return new MyBinaryResultRow(newConverters, newSlices);
    }

    public int size() {
        return fieldSlices.size();
    }

    public DecodedMeta getValueFunction(int itemNumber) {
        return fieldConverters.get(itemNumber);
    }

    public ByteBuf getSlice(int itemNumber) {
        ByteBuf field = fieldSlices.get(itemNumber);
        if (field == null)
            return null;
        else
            return field.slice();
    }

    public boolean isNull(int itemNumber) {
        return fieldSlices.get(itemNumber) == null;
    }

    public Object getValue(int itemNumber) throws PEException {
        ByteBuf slice = getSlice(itemNumber);
        if (slice == null)
            return null;
        else
            return fieldConverters.get(itemNumber).readObject(slice);
    }

    public int sizeInBytes() {
        int totalSize = super.MESSAGE_HEADER_LENGTH;
        totalSize += 1;
        totalSize += MyNullBitmap.computeSize(fieldSlices.size(), MyNullBitmap.BitmapType.RESULT_ROW);
        for (int i = 0; i < fieldSlices.size(); i++) {
            ByteBuf fieldSlice = fieldSlices.get(i);
            if (fieldSlice != null)
                totalSize += fieldSlice.readableBytes();
        }
        return totalSize;
    }
}