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

io.journalkeeper.core.transaction.TransactionEntrySerializer Maven / Gradle / Ivy

There is a newer version: 0.1.11
Show newest version
/**
 * 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 io.journalkeeper.core.transaction;

import io.journalkeeper.base.Serializer;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Stream;


/**
 *  transactionId           16 bytes
 *  timestamp               8 bytes
 *  type                    1 byte
 *  partition               2 bytes
 *  commitOrAbort           1 byte
 *  batchSize               2 bytes
 *  entry                   variable bytes
 *      length              4 bytes
 *      bytes               variable bytes
 *  context map             variable bytes
 *      map size            4 bytes
 *      map entry           variable bytes
 *          key string      variable bytes
 *              length      4 bytes
 *              bytes       variable bytes
 *          value string    variable bytes
 *              length      4 bytes
 *              bytes       variable bytes
 *      map entry           variable bytes
 *      map entry           variable bytes
 *
 *
 * @author LiYue
 * Date: 2019/10/22
 */
public class TransactionEntrySerializer implements Serializer {
    private static final int FIXED_LENGTH = 30;

    @Override
    public byte[] serialize(TransactionEntry entry) {
        int size = FIXED_LENGTH +
                Integer.BYTES + (entry.getEntry() == null ? 0 : entry.getEntry().length) +
                Integer.BYTES + (
                        entry.getContext() == null ? 0 :
                                Stream.concat(entry.getContext().keySet().stream(), entry.getContext().values().stream())
                                .mapToInt(s -> Integer.BYTES + s.getBytes(StandardCharsets.UTF_8).length).sum()
        );

        byte [] bytes = new byte[size];
        ByteBuffer buffer = ByteBuffer.wrap(bytes);

        // transactionId
        serializeUUID(entry.getTransactionId(), buffer);

        // timestamp
        buffer.putLong(entry.getTimestamp());

        // type
        buffer.put((byte )entry.getType().value());

        // partition
        buffer.putShort((short) entry.getPartition());
        // commitOrAbort
        buffer.put(entry.isCommitOrAbort() ? (byte ) 1 : (byte) 0);
        // batchSize
        buffer.putShort((short) entry.getBatchSize());
        // entry
        if(entry.getEntry() == null) {
            buffer.putInt(-1);
        } else {
            buffer.putInt(entry.getEntry().length);
            buffer.put(entry.getEntry());
        }
        // context
        if(entry.getContext() == null) {
            buffer.putInt(-1);
        } else {
            buffer.putInt(entry.getContext().size());
            entry.getContext().entrySet().stream()
                    .flatMap(e -> Stream.of(e.getKey(), e.getValue()))
            .forEach(s -> {
                byte [] sb = s.getBytes(StandardCharsets.UTF_8);
                buffer.putInt(sb.length);
                buffer.put(sb);
            });
        }

        return bytes;
    }

    private void serializeUUID(UUID uuid, ByteBuffer buffer) {
        long mostSigBits = 0L;
        long leastSigBits = 0L;
        if(null != uuid) {
            mostSigBits = uuid.getMostSignificantBits();
            leastSigBits = uuid.getLeastSignificantBits();
        }
        buffer.putLong(mostSigBits);
        buffer.putLong(leastSigBits);
    }

    private UUID parseUUID(ByteBuffer buffer) {
        long mostSigBits = buffer.getLong();
        long leastSigBits = buffer.getLong();

        if (mostSigBits == 0L && leastSigBits == 0L) {
            return null;
        } else {
            return new UUID(mostSigBits, leastSigBits);
        }

    }

    @Override
    public TransactionEntry parse(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        byte [] entryBytes = null;
        buffer.position(FIXED_LENGTH);
        int length = buffer.getInt();
        if(length >= 0) {
            entryBytes = new byte[length];
            buffer.get(entryBytes);
        }
        Map context = null;
        int size = buffer.getInt();
        if (size >= 0) {
            context = new HashMap<>(size);
            for (int i = 0; i < size; i++) {
                context.put(getString(buffer), getString(buffer));
            }
        }

        buffer.clear();
        return new TransactionEntry(
                parseUUID(buffer),
                buffer.getLong(),
                TransactionEntryType.valueOf(buffer.get()),
                buffer.getShort(),
                buffer.get() == (byte) 1,
                buffer.getShort(),
                entryBytes,
                context
        );
    }

    private String getString(ByteBuffer buffer) {
        int length = buffer.getInt();
        if(length >= 0) {
            byte [] bytes = new byte[length];
            buffer.get(bytes);
            return new String(bytes, StandardCharsets.UTF_8);
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy