com.yandex.yoctodb.v1.mutable.segment.AbstractV1FullIndex.java Source code

Java tutorial

Introduction

Here is the source code for com.yandex.yoctodb.v1.mutable.segment.AbstractV1FullIndex.java

Source

/*
 * (C) YANDEX LLC, 2014-2016
 *
 * The Source Code called "YoctoDB" available at
 * https://github.com/yandex/yoctodb is subject to the terms of the
 * Mozilla Public License, v. 2.0 (hereinafter referred to as the "License").
 *
 * A copy of the License is also available at http://mozilla.org/MPL/2.0/.
 */

package com.yandex.yoctodb.v1.mutable.segment;

import com.google.common.collect.TreeMultimap;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.yandex.yoctodb.util.OutputStreamWritable;
import com.yandex.yoctodb.util.UnsignedByteArray;
import com.yandex.yoctodb.util.mutable.ByteArraySortedSet;
import com.yandex.yoctodb.util.mutable.IndexToIndexMap;
import com.yandex.yoctodb.util.mutable.IndexToIndexMultiMap;
import com.yandex.yoctodb.util.mutable.impl.FixedLengthByteArraySortedSet;
import com.yandex.yoctodb.util.mutable.impl.IntIndexToIndexMap;
import com.yandex.yoctodb.util.mutable.impl.IntIndexToIndexMultiMap;
import com.yandex.yoctodb.util.mutable.impl.VariableLengthByteArraySortedSet;
import com.yandex.yoctodb.v1.V1DatabaseFormat;
import net.jcip.annotations.NotThreadSafe;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * Index supporting filtering and sorting by specific field
 *
 * @author incubos
 */
@NotThreadSafe
abstract class AbstractV1FullIndex extends Freezable implements IndexSegment {
    @NotNull
    private final byte[] fieldName;
    private final boolean fixedLength;
    private TreeMultimap<UnsignedByteArray, Integer> valueToDocuments = TreeMultimap.create();
    private Map<Integer, UnsignedByteArray> documentToValue = new HashMap<>();
    private int currentDocumentId = 0;
    private final V1DatabaseFormat.SegmentType segmentType;

    AbstractV1FullIndex(@NotNull final String fieldName, final boolean fixedLength,
            @NotNull final V1DatabaseFormat.SegmentType segmentType) {
        this.fieldName = fieldName.getBytes();
        this.fixedLength = fixedLength;
        this.segmentType = segmentType;
    }

    @NotNull
    @Override
    public IndexSegment addDocument(final int documentId, @NotNull final Collection<UnsignedByteArray> values) {
        if (documentId != currentDocumentId)
            throw new IllegalArgumentException(
                    "Wrong document ID <" + documentId + ">. Expecting <" + currentDocumentId + ">.");
        if (values.size() != 1)
            throw new IllegalArgumentException("Expecting a single value");

        checkNotFrozen();

        final UnsignedByteArray value = values.iterator().next();
        valueToDocuments.put(value, documentId);
        documentToValue.put(documentId, value);
        currentDocumentId++;

        return this;
    }

    @Override
    public void setDatabaseDocumentsCount(final int documentsCount) {
        // Ignoring the hint
    }

    @NotNull
    @Override
    public OutputStreamWritable buildWritable() {
        checkNotFrozen();

        freeze();

        // Building index

        final IndexToIndexMultiMap valueToDocumentsIndex = new IntIndexToIndexMultiMap(
                valueToDocuments.asMap().values());

        final ByteArraySortedSet values;
        if (fixedLength) {
            values = new FixedLengthByteArraySortedSet(valueToDocuments.keySet());
        } else {
            values = new VariableLengthByteArraySortedSet(valueToDocuments.keySet());
        }

        final IndexToIndexMap documentToValueIndex = new IntIndexToIndexMap();
        for (Map.Entry<Integer, UnsignedByteArray> entry : documentToValue.entrySet()) {
            documentToValueIndex.put(entry.getKey(), values.indexOf(entry.getValue()));
        }

        // Free memory
        valueToDocuments = null;
        documentToValue = null;

        return new OutputStreamWritable() {
            @Override
            public long getSizeInBytes() {
                return 4L + // Field name
                fieldName.length + 8 + // Values
                values.getSizeInBytes() + 8 + // Value to documents
                valueToDocumentsIndex.getSizeInBytes() + 8 + // Document to value
                documentToValueIndex.getSizeInBytes();
            }

            @Override
            public void writeTo(@NotNull final OutputStream os) throws IOException {
                os.write(Longs.toByteArray(getSizeInBytes()));

                // Payload segment type
                os.write(Ints.toByteArray(segmentType.getCode()));

                // Field name
                os.write(Ints.toByteArray(fieldName.length));
                os.write(fieldName);

                // Values
                os.write(Longs.toByteArray(values.getSizeInBytes()));
                values.writeTo(os);

                // Value to documents
                os.write(Longs.toByteArray(valueToDocumentsIndex.getSizeInBytes()));
                valueToDocumentsIndex.writeTo(os);

                // Document to value
                os.write(Longs.toByteArray(documentToValueIndex.getSizeInBytes()));
                documentToValueIndex.writeTo(os);
            }
        };
    }
}