io.horizondb.model.core.blocks.AbstractDataBlock.java Source code

Java tutorial

Introduction

Here is the source code for io.horizondb.model.core.blocks.AbstractDataBlock.java

Source

/**
 * 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.horizondb.model.core.blocks;

import io.horizondb.io.buffers.Buffers;
import io.horizondb.model.core.DataBlock;
import io.horizondb.model.core.Field;
import io.horizondb.model.core.Record;
import io.horizondb.model.core.iterators.BinaryTimeSeriesRecordIterator;
import io.horizondb.model.core.records.BlockHeaderUtils;
import io.horizondb.model.core.records.TimeSeriesRecord;
import io.horizondb.model.schema.TimeSeriesDefinition;

import java.io.IOException;

import com.google.common.collect.ImmutableRangeMap;
import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;

import static io.horizondb.model.core.iterators.BlockIterators.singleton;

/**
 * Base class for the <code>DataBlock</code> implementations.
 *
 */
public abstract class AbstractDataBlock implements DataBlock {

    /**
     * {@inheritDoc}
     */
    @Override
    public final RangeMap<Field, DataBlock> split(TimeSeriesDefinition definition) throws IOException {

        Range<Field> range = BlockHeaderUtils.getRange(getHeader());

        Range<Field> partitionRange = definition.getPartitionTimeRange(range.lowerEndpoint());

        if (partitionRange.contains(range.upperEndpoint())) {
            return ImmutableRangeMap.<Field, DataBlock>of(partitionRange, this);
        }

        TimeSeriesRecord[] records = definition.newRecords();

        ImmutableRangeMap.Builder<Field, DataBlock> builder = ImmutableRangeMap.builder();

        RecordAppender appender = new RecordAppender(definition, Buffers.getDefaultAllocator(), records);

        Field[] timestamps = new Field[records.length];
        for (int i = 0; i < timestamps.length; i++) {
            timestamps[i] = definition.newField(Record.TIMESTAMP_FIELD_NAME);
        }

        try (BinaryTimeSeriesRecordIterator iterator = new BinaryTimeSeriesRecordIterator(definition,
                singleton(this))) {

            while (iterator.hasNext()) {

                Record record = iterator.next();
                Field timestamp = timestamps[record.getType()];
                if (record.isDelta()) {
                    timestamp.add(record.getField(Record.TIMESTAMP_FIELD_INDEX));
                } else {
                    record.getField(Record.TIMESTAMP_FIELD_INDEX).copyTo(timestamp);
                }

                if (!partitionRange.contains(timestamp)) {

                    builder.put(partitionRange, appender.getDataBlock());
                    partitionRange = definition.getPartitionTimeRange(timestamp);
                    appender = new RecordAppender(definition, Buffers.getDefaultAllocator(), records);
                }
                appender.append(record);
            }
            builder.put(partitionRange, appender.getDataBlock());
        }

        return builder.build();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public long getFirstTimestamp() throws IOException {
        return BlockHeaderUtils.getFirstTimestamp(getHeader());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public long getLastTimestamp() throws IOException {
        return BlockHeaderUtils.getLastTimestamp(getHeader());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final boolean isAfter(DataBlock block) throws IOException {
        return getFirstTimestamp() > block.getLastTimestamp();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final boolean overlap(DataBlock block) throws IOException {

        long timestamp = getFirstTimestamp();
        long otherTimestamp = block.getFirstTimestamp();

        if (timestamp < otherTimestamp) {
            return otherTimestamp <= getLastTimestamp();
        }
        return timestamp <= block.getLastTimestamp();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final boolean hasSpaceAvailable(TimeSeriesDefinition definition) throws IOException {

        long blockSize = BlockHeaderUtils.getUncompressedBlockSize(getHeader());
        long averageRecordSize = blockSize / getNumberOfRecords(definition);
        // If we have at least twice the space of an average record we should be able 
        // to add an extra one.
        return (blockSize + (2 * averageRecordSize)) <= definition.getBlockSizeInBytes();
    }

    /**
     * Returns the total number of records within this block.
     *
     * @return the total number of records within this block.
     * @throws IOException if an I/O problem occurs
     */
    private long getNumberOfRecords(TimeSeriesDefinition definition) throws IOException {
        int numberOfRecords = 0;
        for (int i = 0; i < definition.getNumberOfRecordTypes(); i++) {
            numberOfRecords += BlockHeaderUtils.getRecordCount(getHeader(), i);
        }
        return numberOfRecords;
    }
}