Package com.netflix.zeno.fastblob.io

Source Code of com.netflix.zeno.fastblob.io.FastBlobWriter

/*
*
*  Copyright 2013 Netflix, 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.netflix.zeno.fastblob.io;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import com.netflix.zeno.fastblob.FastBlobStateEngine;
import com.netflix.zeno.fastblob.record.VarInt;
import com.netflix.zeno.fastblob.state.FastBlobTypeDeserializationState;
import com.netflix.zeno.fastblob.state.FastBlobTypeSerializationState;
import com.netflix.zeno.fastblob.state.ThreadSafeBitSet;

/**
* Writes FastBlob images to streams.
*/
public class FastBlobWriter {

    private final FastBlobStateEngine stateEngine;
    private final int imageIndex;
    private FastBlobHeaderWriter headerWriter;

    public FastBlobWriter(FastBlobStateEngine stateEngine) {
        this(stateEngine, 0);
    }

    public FastBlobWriter(FastBlobStateEngine stateEngine, int imageIndex) {
        this(stateEngine, imageIndex, new ZenoFastBlobHeaderWriter());
    }

    public void setFastBlobHeaderWriter(FastBlobHeaderWriter headerWriter) {
        this.headerWriter = headerWriter;
    }

    /**
     * This FastBlobWriter will write a single image to a stream, as either a snapshot or delta.<p/>
     *
     * The configuration for the image which this will write is contained in the list returned by <code>stateEngine.getImageConfigurations()</code>
     * at the index specified by <code>imageIndex</code>
     *
     * @param stateEngine
     * @param imageIndex
     */
    public FastBlobWriter(FastBlobStateEngine stateEngine, int imageIndex, FastBlobHeaderWriter headerWriter) {
        this.stateEngine = stateEngine;
        this.imageIndex = imageIndex;
        this.headerWriter = headerWriter;
    }

    /**
     * Write a snapshot to the specified stream.
     */
    public void writeSnapshot(OutputStream os) throws Exception {
        writeSnapshot(new DataOutputStream(os));
    }

    public void writeSnapshot(DataOutputStream os) throws IOException {
        writeHeader(os);

        for(FastBlobTypeSerializationState<?> typeState : stateEngine.getOrderedSerializationStates()) {
            if(!typeState.isReadyForWriting())
                throw new RuntimeException("This state engine is not ready for writing! Have you remembered to call stateEngine.prepareForWrite()?");

            /// type flags byte -- reserved for later use
            os.write(0);
            /// write the schema
            typeState.getSchema().writeTo(os);

            ThreadSafeBitSet imageMembershipBitSet = typeState.getImageMembershipBitSet(imageIndex);
            serializeTypeStateObjects(os, typeState, imageMembershipBitSet);
        }
    }

    public void writeNonImageSpecificSnapshot(DataOutputStream os) throws IOException {
        writeHeader(os);

        for(FastBlobTypeSerializationState<?> typeState : stateEngine.getOrderedSerializationStates()) {
            if(!typeState.isReadyForWriting())
                throw new RuntimeException("This state engine is not ready for writing! Have you remembered to call stateEngine.prepareForWrite()?");

            FastBlobTypeDeserializationState<?> typeDeserializationState = stateEngine.getTypeDeserializationState(typeState.getSchema().getName());

            /// type flags byte -- reserved for later use
            os.write(0);
            /// write the schema
            typeState.getSchema().writeTo(os);

            serializeTypeStateObjects(os, typeState, typeDeserializationState);
        }
    }

    /**
     * Write a delta to the specified stream.
     */
    public void writeDelta(OutputStream os) throws IOException {
        writeDelta(new DataOutputStream(os));
    }

    public void writeDelta(DataOutputStream os) throws IOException {
        writeHeader(os);

        for(FastBlobTypeSerializationState<?> typeState : stateEngine.getOrderedSerializationStates()) {
            if(!typeState.isReadyForWriting())
                throw new RuntimeException("This state engine is not ready for writing! Have you remembered to call stateEngine.prepareForWrite()?");

            /// type flags byte -- reserved for later use
            os.write(0);
            /// write the schema
            typeState.getSchema().writeTo(os);

            ThreadSafeBitSet currentImageMembershipBitSet = typeState.getImageMembershipBitSet(imageIndex);
            ThreadSafeBitSet previousImageMembershipBitSet = typeState.getPreviousCycleImageMembershipBitSet(imageIndex);

            serializeDelta(os, typeState, currentImageMembershipBitSet, previousImageMembershipBitSet);
        }
    }

    /**
     * Write a reverse delta to the specified stream.
     *
     * A reverse delta is the opposite of a delta.  A delta removes all unused objects from the previous state and adds all
     * new objects in the current state.  A reverse delta removes all new objects in the current state and adds all unused
     * objects from the previous state.
     */
    public void writeReverseDelta(OutputStream os, String previousVersion) throws IOException {
        writeReverseDelta(new DataOutputStream(os), previousVersion);
    }

    public void writeReverseDelta(DataOutputStream os, String previousVersion) throws IOException {
        writeHeader(os, previousVersion);

        for(FastBlobTypeSerializationState<?> typeState : stateEngine.getOrderedSerializationStates()) {
            if(!typeState.isReadyForWriting())
                throw new RuntimeException("This state engine is not ready for writing! Have you remembered to call stateEngine.prepareForWrite()?");

            if(typeState.getPreviousStateSchema() != null) {
                /// type flags byte -- reserved for later use
                os.write(0);
                /// write the schema
                typeState.getPreviousStateSchema().writeTo(os);

                ThreadSafeBitSet currentImageMembershipBitSet = typeState.getImageMembershipBitSet(imageIndex);
                ThreadSafeBitSet previousImageMembershipBitSet = typeState.getPreviousCycleImageMembershipBitSet(imageIndex);

                serializeDelta(os, typeState, previousImageMembershipBitSet, currentImageMembershipBitSet);
            }
        }
    }

    private void serializeDelta(DataOutputStream os, FastBlobTypeSerializationState<?> typeState, ThreadSafeBitSet currentStateOrdinals, ThreadSafeBitSet prevStateOrdinals) throws IOException {
        /// get all of the ordinals contained in the previous cycle, which are no longer contained in this cycle.  These all need to be removed.
        ThreadSafeBitSet removedTypeStateObjectsBitSet = prevStateOrdinals.andNot(currentStateOrdinals);
        serializeTypeStateRemovals(os, removedTypeStateObjectsBitSet);

        /// get all of the ordinals contained in this cycle, which were not contained in the previous cycle.  These all need to be added.
        ThreadSafeBitSet addedTypeStateObjectsBitSet = currentStateOrdinals.andNot(prevStateOrdinals);
        serializeTypeStateObjects(os, typeState, addedTypeStateObjectsBitSet);
    }

    private void writeHeader(DataOutputStream os) throws IOException {
        String version = stateEngine.getLatestVersion() != null ? stateEngine.getLatestVersion() : "";
        writeHeader(os, version);
    }

    private void writeHeader(DataOutputStream os, String version) throws IOException {
        FastBlobHeader header = new FastBlobHeader();
        header.setVersion(version);
        header.setHeaderTags(stateEngine.getHeaderTags());

        /// The deserialization StreamingByteData buffer size needs to accommodate the largest single object.
        /// write the ceil(log2(maxSize)) as a single byte at the beginning of the stream.
        /// upon deserialization, this byte will be read and the StreamingByteData buffer can be sized appropriately.
        int deserializationBufferSizeHint = 32 - Integer.numberOfLeadingZeros(stateEngine.getMaxSingleObjectLength() - 1);
        header.setDeserializationBufferSizeHint(deserializationBufferSizeHint);

        header.setNumberOfTypes(stateEngine.getOrderedSerializationStates().size());

        headerWriter.writeHeader(header,stateEngine,os);
    }

    private void serializeTypeStateObjects(DataOutputStream os, FastBlobTypeSerializationState<?> typeState, ThreadSafeBitSet includeOrdinals) throws IOException {
        int currentBitSetCapacity = includeOrdinals.currentCapacity();
        int currentOrdinal = 0;

        /// write the number of objects
        VarInt.writeVInt(os, includeOrdinals.cardinality());

        for(int i=0;i<currentBitSetCapacity;i++) {
            if(includeOrdinals.get(i)) {
                /// gap-encoded ordinals
                VarInt.writeVInt(os, i - currentOrdinal);
                currentOrdinal = i;

                /// typeState will use the ByteArrayOrdinalMap to write the length and
                /// serialized representation of the object.
                typeState.writeObjectTo(os, i);
            }
        }
    }

    private void serializeTypeStateObjects(DataOutputStream os, FastBlobTypeSerializationState<?> typeState,
            FastBlobTypeDeserializationState<?> typeDeserializationState) throws IOException {
        /// write the number of objects
        VarInt.writeVInt(os, typeDeserializationState.countObjects());
        int currentOrdinal = 0;

        for(int i=0;i<=typeDeserializationState.maxOrdinal();i++) {
            Object obj = typeDeserializationState.get(i);
            if(obj != null) {
                /// gap-encoded ordinals
                VarInt.writeVInt(os, i - currentOrdinal);
                currentOrdinal = i;

                /// typeState will use the ByteArrayOrdinalMap to write the length and
                /// serialized representation of the object.
                typeState.writeObjectTo(os, i);
            }
        }
    }

    private void serializeTypeStateRemovals(DataOutputStream os, ThreadSafeBitSet removals) throws IOException {
        int bitSetCapacity = removals.currentCapacity();
        int currentRemoval = 0;

        /// write the number of removals
        VarInt.writeVInt(os, removals.cardinality());

        for(int i=0;i<bitSetCapacity;i++) {
            if(removals.get(i)) {
                /// gap-encoded ordinals
                VarInt.writeVInt(os, i - currentRemoval);
                currentRemoval = i;
            }
        }
    }

}
TOP

Related Classes of com.netflix.zeno.fastblob.io.FastBlobWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.