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

com.bigdata.bfs.FileVersionInputStream Maven / Gradle / Ivy

package com.bigdata.bfs;

import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;

import com.bigdata.btree.ITuple;
import com.bigdata.btree.ITupleIterator;
import com.bigdata.btree.keys.KeyBuilder;
import com.bigdata.rawstore.IBlock;
import com.bigdata.util.Bytes;

/**
 * Reads from blocks visited by a range scan for a file and version.
 * 
 * @author Bryan Thompson
 * @version $Id$
 */
public class FileVersionInputStream extends InputStream {

    protected final String id;

    protected final int version;

    private final ITupleIterator src;

    /**
     * The current block# whose data are being read.
     */
    private long block;

    /**
     * A buffer holding the current block's data. This is initially filled
     * from the first block by the ctor. When no more data is available it
     * is set to null to indicate that the input stream has
     * been exhausted.
     * 
     * @todo reuse buffers sized out to the block size.
     */
    private byte[] b;

    /**
     * The next byte to be returned from the current block's data.
     */
    private int off;

    /**
     * The #of bytes remaining in the current block's data.
     */
    private int len;

    /**
     * The file identifier.
     */
    public String getId() {

        return id;

    }

    /**
     * The file version identifer.
     */
    public int getVersion() {

        return version;

    }

    /**
     * The current block identifier.
     */
    public long getBlock() {

        return block;

    }

    public FileVersionInputStream(String id, int version, ITupleIterator src) {

        this.id = id;

        this.version = version;

        this.src = src;

        // read the first block of data.
        nextBlock();

    }

    /**
     * Reads the next block of data from the iterator and sets it on the
     * internal buffer. If the iterator is exhausted then the internal
     * buffer is set to null.
     * 
     * @return true iff another block of data was read.
     */
    private boolean nextBlock() {

        assert b == null || off == len;

        if (!src.hasNext()) {

            BigdataFileSystem.log.info("No more blocks: id=" + id
                    + ", version=" + version);

            b = null;

            off = 0;

            len = 0;

            return false;

        }

        final ITuple tuple = src.next();

        /*
         * decode the block address.
         */
        final long addr;
        try {

            DataInput in = tuple.getValueStream();

            addr = in.readLong();

        } catch (IOException e) {

            throw new RuntimeException(e);

        }

        if (addr == 0L) {

            /*
             * Note: empty blocks are allowed and are recorded with 0L as
             * their address.
             */

            b = new byte[] {};

            off = 0;

            len = 0;

            BigdataFileSystem.log.info("Read zero bytes: id=" + id
                    + ", version=" + version + ", block=" + block);

        } else {

            byte[] key = tuple.getKey();

            // decode the block identifier from the key.
            //                block = KeyBuilder.decodeLong(tuple.getKeyBuffer().array(),
            //                        tuple.getKeyBuffer().pos() - Bytes.SIZEOF_LONG);
            block = KeyBuilder.decodeLong(key, key.length - Bytes.SIZEOF_LONG);

            final IBlock tmp = tuple.readBlock(addr);

            final int nbytes = tmp.length();

            // @todo reuse buffer!
            b = new byte[nbytes];

            off = 0;

            len = nbytes;

            try {

                final int nread = tmp.inputStream().read(b, off, len);

                if (nread != len) {

                    throw new RuntimeException("Expecting " + len
                            + " bytes but read " + nread);

                }

            } catch (IOException e) {

                throw new RuntimeException(e);

            }

            BigdataFileSystem.log.info("Read " + b.length + " bytes: id=" + id
                    + ", version=" + version + ", block=" + block);

        }

        return true;

    }

    public int read() throws IOException {

        if (b == null) {

            // nothing left to read.

            return -1;

        }

        if (off == len) {

            if (!nextBlock()) {

                // no more blocks so nothing left to read.

                return -1;

            }

        }

        // the next byte.
        int v = (0xff & b[off++]);

        return v;

    }

    /**
     * Overriden for greater efficiency.
     */
    public int read(byte[] b, int off, int len) throws IOException {

        if (b == null) {

            // nothing left to read.

            return -1;

        }

        if (this.off == this.len) {

            if (!nextBlock()) {

                // no more blocks so nothing left to read.

                return -1;

            }

        }

        /*
         * Copy everything in our internal buffer up to the #of bytes
         * remaining in the caller's buffer.
         */

        final int n = Math.min(this.len, len);

        System.arraycopy(this.b, this.off, b, off, n);

        this.off += n;

        return n;

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy