<commit_before>/**
 * 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.operator.StoreAdapter;
import com.foundationdb.qp.row.HKey;
import com.foundationdb.qp.row.Row;
import com.foundationdb.qp.rowtype.Schema;
import com.foundationdb.qp.util.SchemaCache;
import com.foundationdb.server.store.FDBScanTransactionOptions;
import com.foundationdb.server.store.FDBStoreData;
import com.foundationdb.util.tap.PointTap;
import com.foundationdb.util.tap.Tap;

public class FDBGroupCursor extends RowCursorImpl implements GroupCursor {
    private final FDBAdapter adapter;
    private final FDBStoreData storeData;
    private final Schema schema;
    private HKey hKey;
    private boolean hKeyDeep;
    private GroupScan groupScan;
    private int commitFrequency;
    // static state
    private static final PointTap TRAVERSE_COUNT = Tap.createCount("traverse: fdb group cursor");


    public FDBGroupCursor(FDBAdapter adapter, Group group) {
        this.adapter = adapter;
        this.storeData = adapter.getUnderlyingStore()
            .createStoreData(adapter.getSession(), group);
        this.schema = SchemaCache.globalSchema(group.getAIS());
    }

    public FDBGroupCursor(FDBAdapter adapter, Group group, int commitFrequency) {
        this(adapter, group);
        this.commitFrequency = commitFrequency;
    }

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

    @Override
    public void open() {
        super.open();
        if(commitFrequency != 0) {
            groupScan = new CommittingFullScan();
        } else if(hKey == null) {
            groupScan = new FullScan();
        } else if(hKeyDeep) {
            groupScan = new HKeyAndDescendantScan(hKey);
        } else {
            groupScan = new HKeyWithoutDescendantScan(hKey);
        }
    }

    @Override
    public FDBGroupRow next() {
        CursorLifecycle.checkIdleOrActive(this);
        boolean next = isActive();
        FDBGroupRow row = null;
        if (next) {
            groupScan.advance();
            next = isActive();
            if (next) {
                Row tempRow = adapter.getUnderlyingStore().expandGroupData(adapter.getSession(), storeData, schema);
                row = new FDBGroupRow(adapter.getKeyCreator(), tempRow, storeData.persistitKey);
            }
        }
        return row;
    }

    @Override
    public void close() {
        groupScan = null;
        super.close();
    }

    private abstract class GroupScan {
        public void advance() {
            TRAVERSE_COUNT.hit();
            if (!storeData.next()) {
                setIdle();
            }
        }
    }

    private class FullScan extends GroupScan {
        public FullScan() {
            adapter.getUnderlyingStore().groupIterator(adapter.getSession(), storeData);
        }
    }

    private class HKeyAndDescendantScan extends GroupScan {
        public HKeyAndDescendantScan(HKey hKey) {
            hKey.copyTo(storeData.persistitKey.clear());
            adapter.getUnderlyingStore().groupKeyAndDescendantsIterator(adapter.getSession(), storeData, false);
        }
    }

    private class HKeyWithoutDescendantScan extends GroupScan
    {
        boolean first = true;

        @Override
        public void advance()
        {
            if(first) {
                super.advance();
                first = false;
            } else {
                setIdle();
            }
        }

        public HKeyWithoutDescendantScan(HKey hKey)
        {
            hKey.copyTo(storeData.persistitKey.clear());
            adapter.getUnderlyingStore().groupKeyIterator(adapter.getSession(), storeData);
        }
    }

    private class CommittingFullScan extends GroupScan {
        public CommittingFullScan() {
            FDBScanTransactionOptions transactionOptions;
            if (commitFrequency == StoreAdapter.COMMIT_FREQUENCY_PERIODICALLY) {
                transactionOptions = adapter.getTransaction().periodicallyCommitScanOptions();
            }
            else {
                transactionOptions = new FDBScanTransactionOptions(commitFrequency, -1);
            }
            adapter.getUnderlyingStore().groupIterator(adapter.getSession(), storeData, transactionOptions);
        }
    }

}<commit_msg>Adjust constructor a little to make testing easier.<commit_after>/**
 * 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.operator.StoreAdapter;
import com.foundationdb.qp.row.HKey;
import com.foundationdb.qp.row.Row;
import com.foundationdb.qp.rowtype.Schema;
import com.foundationdb.qp.util.SchemaCache;
import com.foundationdb.server.store.FDBScanTransactionOptions;
import com.foundationdb.server.store.FDBStoreData;
import com.foundationdb.util.tap.PointTap;
import com.foundationdb.util.tap.Tap;

public class FDBGroupCursor extends RowCursorImpl implements GroupCursor {
    private final FDBAdapter adapter;
    private final FDBStoreData storeData;
    private final Schema schema;
    private final FDBScanTransactionOptions transactionOptions;
    private HKey hKey;
    private boolean hKeyDeep;
    private GroupScan groupScan;
    // static state
    private static final PointTap TRAVERSE_COUNT = Tap.createCount("traverse: fdb group cursor");

    public FDBGroupCursor(FDBAdapter adapter, Group group) {
        this(adapter, group, null);
    }

    public FDBGroupCursor(FDBAdapter adapter, Group group, int commitFrequency) {
        this(adapter, group, optionsForFrequency(commitFrequency, adapter));
    }

    private static FDBScanTransactionOptions optionsForFrequency(int commitFrequency, FDBAdapter adapter) {
        if (commitFrequency == 0) {
            return null;
        }
        else if (commitFrequency == StoreAdapter.COMMIT_FREQUENCY_PERIODICALLY) {
            return adapter.getTransaction().periodicallyCommitScanOptions();
        }
        else {
            return new FDBScanTransactionOptions(commitFrequency, -1);
        }
    }

    public FDBGroupCursor(FDBAdapter adapter, Group group, FDBScanTransactionOptions transactionOptions) {
        this.adapter = adapter;
        this.storeData = adapter.getUnderlyingStore()
            .createStoreData(adapter.getSession(), group);
        this.schema = SchemaCache.globalSchema(group.getAIS());
        this.transactionOptions = transactionOptions;
    }

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

    @Override
    public void open() {
        super.open();
        if(transactionOptions != null) {
            groupScan = new CommittingFullScan();
        } else if(hKey == null) {
            groupScan = new FullScan();
        } else if(hKeyDeep) {
            groupScan = new HKeyAndDescendantScan(hKey);
        } else {
            groupScan = new HKeyWithoutDescendantScan(hKey);
        }
    }

    @Override
    public FDBGroupRow next() {
        CursorLifecycle.checkIdleOrActive(this);
        boolean next = isActive();
        FDBGroupRow row = null;
        if (next) {
            groupScan.advance();
            next = isActive();
            if (next) {
                Row tempRow = adapter.getUnderlyingStore().expandGroupData(adapter.getSession(), storeData, schema);
                row = new FDBGroupRow(adapter.getKeyCreator(), tempRow, storeData.persistitKey);
            }
        }
        return row;
    }

    @Override
    public void close() {
        groupScan = null;
        super.close();
    }

    private abstract class GroupScan {
        public void advance() {
            TRAVERSE_COUNT.hit();
            if (!storeData.next()) {
                setIdle();
            }
        }
    }

    private class FullScan extends GroupScan {
        public FullScan() {
            adapter.getUnderlyingStore().groupIterator(adapter.getSession(), storeData);
        }
    }

    private class HKeyAndDescendantScan extends GroupScan {
        public HKeyAndDescendantScan(HKey hKey) {
            hKey.copyTo(storeData.persistitKey.clear());
            adapter.getUnderlyingStore().groupKeyAndDescendantsIterator(adapter.getSession(), storeData, false);
        }
    }

    private class HKeyWithoutDescendantScan extends GroupScan
    {
        boolean first = true;

        @Override
        public void advance()
        {
            if(first) {
                super.advance();
                first = false;
            } else {
                setIdle();
            }
        }

        public HKeyWithoutDescendantScan(HKey hKey)
        {
            hKey.copyTo(storeData.persistitKey.clear());
            adapter.getUnderlyingStore().groupKeyIterator(adapter.getSession(), storeData);
        }
    }

    private class CommittingFullScan extends GroupScan {
        public CommittingFullScan() {
            adapter.getUnderlyingStore().groupIterator(adapter.getSession(), storeData, transactionOptions);
        }
    }

}
{'fraction_non_alphanumeric': 0.0861090775988287, 'fraction_numerical': 0.002013177159590044, 'mean_word_length': 2.596248766041461, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2374785', 'n_tokens_mistral': 2983, 'n_tokens_neox': 2889, 'n_words': 739}