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

com.questdb.iter.JournalConcurrentIterator Maven / Gradle / Ivy

There is a newer version: 3.3.3
Show newest version
/*******************************************************************************
 *    ___                  _   ____  ____
 *   / _ \ _   _  ___  ___| |_|  _ \| __ )
 *  | | | | | | |/ _ \/ __| __| | | |  _ \
 *  | |_| | |_| |  __/\__ \ |_| |_| | |_) |
 *   \__\_\\__,_|\___||___/\__|____/|____/
 *
 * Copyright (C) 2014-2016 Appsicle
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 *
 ******************************************************************************/

package com.questdb.iter;

import com.questdb.Journal;
import com.questdb.ex.JournalException;
import com.questdb.ex.JournalRuntimeException;
import com.questdb.misc.NamedDaemonThreadFactory;
import com.questdb.misc.Rows;
import com.questdb.mp.RingQueue;
import com.questdb.mp.SCSequence;
import com.questdb.mp.SPSequence;
import com.questdb.mp.Sequence;
import com.questdb.std.ObjList;
import com.questdb.std.ObjectFactory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class JournalConcurrentIterator extends com.questdb.std.AbstractImmutableIterator
        implements ObjectFactory>, ConcurrentIterator {
    private final Journal journal;
    private final ObjList ranges;
    private final ExecutorService service;
    private RingQueue> buffer;
    private Sequence pubSeq;
    private Sequence subSeq;
    private int bufferSize;
    private boolean started = false;
    private long cursor = -1;

    public JournalConcurrentIterator(Journal journal, ObjList ranges, int bufferSize) {
        this.bufferSize = bufferSize;
        this.service = Executors.newSingleThreadExecutor(new NamedDaemonThreadFactory("questdb-iterator", false));
        this.journal = journal;
        this.ranges = ranges;
    }

    @Override
    public ConcurrentIterator buffer(int bufferSize) {
        this.bufferSize = bufferSize;
        return this;
    }

    @Override
    public void close() {
        service.shutdown();
    }

    @Override
    public Journal getJournal() {
        return journal;
    }

    @Override
    public boolean hasNext() {
        if (!started) {
            start();
            started = true;
        }
        if (cursor >= 0) {
            subSeq.done(cursor);
        }
        this.cursor = subSeq.nextBully();
        return buffer.get(cursor).hasNext;
    }

    @Override
    public T next() {
        return buffer.get(cursor).object;
    }

    @Override
    public Holder newInstance() {
        Holder h = new Holder<>();
        h.object = getJournal().newObject();
        h.hasNext = true;
        return h;
    }

    private Runnable getRunnable() {
        return new Runnable() {

            boolean hasNext = true;
            private int currentIndex = 0;
            private long currentRowID;
            private long currentUpperBound;
            private int currentPartitionID;

            @Override
            public void run() {
                updateVariables();
                while (true) {
                    try {
                        long cursor = pubSeq.nextBully();
                        Holder holder = buffer.get(cursor);
                        boolean hadNext = hasNext;
                        if (hadNext) {
                            journal.read(Rows.toRowID(currentPartitionID, currentRowID), holder.object);
                            if (currentRowID < currentUpperBound) {
                                currentRowID++;
                            } else {
                                currentIndex++;
                                updateVariables();
                            }
                        }
                        holder.hasNext = hadNext;
                        pubSeq.done(cursor);

                        if (!hadNext) {
                            break;
                        }
                    } catch (JournalException e) {
                        throw new JournalRuntimeException("Error in iterator [%s]", e, this);
                    }
                }
            }

            private void updateVariables() {
                if (currentIndex < ranges.size()) {
                    JournalIteratorRange w = ranges.getQuick(currentIndex);
                    currentRowID = w.lo;
                    currentUpperBound = w.hi;
                    currentPartitionID = w.partitionID;
                } else {
                    hasNext = false;
                }
            }

        };
    }

    private void start() {
        this.buffer = new RingQueue<>(this, bufferSize);
        this.pubSeq = new SPSequence(bufferSize);
        this.subSeq = new SCSequence();
        this.pubSeq.then(subSeq).then(pubSeq);
        service.submit(getRunnable());
    }

    protected final static class Holder {
        T object;
        boolean hasNext;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy