Package com.foundationdb.qp.storeadapter

Source Code of com.foundationdb.qp.storeadapter.PersistitGroupCursor

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 <http://www.gnu.org/licenses/>.
*/

package com.foundationdb.qp.storeadapter;

import com.foundationdb.ais.model.Group;
import com.foundationdb.qp.operator.CursorLifecycle;
import com.foundationdb.qp.operator.GroupCursor;
import com.foundationdb.qp.operator.RowCursorImpl;
import com.foundationdb.qp.row.HKey;
import com.foundationdb.qp.row.Row;
import com.foundationdb.server.error.InvalidOperationException;
import com.foundationdb.server.error.PersistitAdapterException;
import com.foundationdb.util.tap.PointTap;
import com.foundationdb.util.tap.Tap;
import com.persistit.Exchange;
import com.persistit.Key;
import com.persistit.exception.PersistitException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
* A PersistitGroupCursor can be used in three ways:
* 1) Scan the entire group: This occurs when there is no binding before open().
* 2) For a given hkey, find the row and its descendents: This occurs when rebind(HKey, true) is called.
* 3) For a given hkey, find the row without its descendents: This occurs when rebind(HKey, false) is called.
*/


class PersistitGroupCursor extends RowCursorImpl implements GroupCursor
{
    // GroupCursor interface

    @Override
    public void rebind(HKey hKey, boolean deep)
    {
        CursorLifecycle.checkClosed(this);
        this.hKey =  hKey;
        this.hKeyDeep = deep;
    }


    // Cursor interface

    @Override
    public void open()
    {
        super.open();
        try {
            this.exchange = adapter.takeExchange(group);
            exchange.clear();
            groupScan =
                hKey == null ? new FullScan() :
                hKeyDeep ? new HKeyAndDescendentsScan(hKey) : new HKeyWithoutDescendentsScan(hKey);
        } catch (PersistitException e) {
            adapter.handlePersistitException(e);
        }
    }

    @Override
    public Row next()
    {
        try {
            CursorLifecycle.checkIdleOrActive(this);
            boolean next = isActive();
            PersistitGroupRow row = null;
            if (next) {
                groupScan.advance();
                next = isActive();
                if (next) {
                    row = adapter.newGroupRow();
                    row.copyFromExchange(exchange);
                }
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug("PersistitGroupCursor: {}", row);
            }
            return row;
        } catch (PersistitException e) {
            adapter.handlePersistitException(e);
            throw new AssertionError();
        } catch (InvalidOperationException e) {
            throw new PersistitAdapterException(e);
        }
    }

    @Override
    public void close()
    {
        groupScan = null;
        if (exchange != null) {
            adapter.returnExchange(exchange);
            exchange = null;
        }
        super.close();
    }

    // For use by this package

    PersistitGroupCursor(PersistitAdapter adapter, Group group)
        throws PersistitException
    {
        this.adapter = adapter;
        this.group = group;
        this.controllingHKey = adapter.newKey();
    }

    // Class state

    private static final Logger LOG = LoggerFactory.getLogger(PersistitGroupCursor.class);

    // Object state

    /*
     * 1) Scan entire group: Initialize exchange to Key.BEFORE and keep going forward, doing a deep traversal,
     *    until there are no more rows.
     *
     * 2) Scan one hkey and descendents: The key is copied to the exchange, to begin the scan, and to controllingHKey
     *    to determine when the scan should end.
     *
     * 3) Scan one hkey without descendents: The key is copied to the exchange.
     *
     *  General:
     *  - exchange == null iff this cursor is idle
     */

    private final PersistitAdapter adapter;
    private final Group group;
    private Exchange exchange;
    private Key controllingHKey;
    private HKey hKey;
    private boolean hKeyDeep;
    private GroupScan groupScan;

    // static state
    private static final PointTap TRAVERSE_COUNT = Tap.createCount("traverse: persistit group cursor");
   
    // Inner classes

    interface GroupScan
    {
        /**
         * Advance the exchange. Close if this causes the exchange to run out of selected rows.
         *
         * @throws PersistitException
         * @throws InvalidOperationException
         */
        void advance() throws PersistitException, InvalidOperationException;
    }

    private class FullScan implements GroupScan
    {
        @Override
        public void advance() throws PersistitException, InvalidOperationException
        {
            TRAVERSE_COUNT.hit();
            if (!exchange.traverse(direction, true)) {
                setIdle();
            }
        }

        public FullScan() throws PersistitException
        {
            exchange.getKey().append(Key.BEFORE);
            direction = Key.GT;
        }

        private final Key.Direction direction;
    }

    private class HKeyAndDescendentsScan implements GroupScan
    {
        @Override
        public void advance() throws PersistitException, InvalidOperationException
        {
            TRAVERSE_COUNT.hit();
            if (!exchange.traverse(direction, true) ||
                exchange.getKey().firstUniqueByteIndex(controllingHKey) < controllingHKey.getEncodedSize()) {
                setIdle();
            }
            direction = Key.GT;
        }

        HKeyAndDescendentsScan(HKey hKey) throws PersistitException
        {
            hKey.copyTo(exchange.getKey());
            hKey.copyTo(controllingHKey);
        }

        private Key.Direction direction = Key.GTEQ;
    }

    private class HKeyWithoutDescendentsScan implements GroupScan
    {
        @Override
        public void advance() throws PersistitException, InvalidOperationException
        {
            if (first) {
                TRAVERSE_COUNT.hit();
                exchange.fetch();
                if (!exchange.getValue().isDefined()) {
                    setIdle();
                }
                first = false;
            } else {
                setIdle();
            }
        }

        HKeyWithoutDescendentsScan(HKey hKey) throws PersistitException
        {
            hKey.copyTo(exchange.getKey());
        }

        private boolean first = true;
    }
}
TOP

Related Classes of com.foundationdb.qp.storeadapter.PersistitGroupCursor

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.