/*
 * Licensed to Crate under one or more contributor license agreements.
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.  Crate licenses this file
 * to you 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.
 *
 * However, if you have executed another commercial license agreement
 * with Crate these terms will supersede the license and you may use the
 * software solely pursuant to the terms of the relevant commercial
 * agreement.
 */

package io.crate.data;

import io.crate.testing.RowGenerator;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
public class RowsBatchIteratorBenchmark {

    // use materialize to not have shared row instances
    // this is done in the startup, otherwise the allocation costs will make up the majority of the benchmark.
    private List<Row> rows = StreamSupport.stream(RowGenerator.range(0, 10_000_000).spliterator(), false)
        .map(Row::materialize)
        .map(RowN::new)
        .collect(Collectors.toList());

    // use RowsBatchIterator without any state/error handling to establish a performance baseline.
    private BatchIterator it = new RowsBatchIterator(rows, 1);

    private BatchIterator itCloseAsserting = new CloseAssertingBatchIterator(it);
    private BatchIterator skippingIt = new SkippingBatchIterator(it, 100);

    @Benchmark
    public void measureConsumeBatchIterator(Blackhole blackhole) throws Exception {
        final Input<?> input = it.rowData().get(0);
        while (it.moveNext()) {
            blackhole.consume(input.value());
        }
        it.moveToStart();
    }

    @Benchmark
    public void measureConsumeCloseAssertingIterator(Blackhole blackhole) throws Exception {
        final Input<?> input = itCloseAsserting.rowData().get(0);
        while (itCloseAsserting.moveNext()) {
            blackhole.consume(input.value());
        }
        itCloseAsserting.moveToStart();
    }

    @Benchmark
    public void measureConsumeSkippingBatchIterator(Blackhole blackhole) throws Exception {
        final Input<?> input = skippingIt.rowData().get(0);
        while (skippingIt.moveNext()) {
            blackhole.consume(input.value());
        }
        skippingIt.moveToStart();
    }
}

@@ -1177,27 +1177,96 @@
 til.
-concurrent.TimeUnit
+Objects;%0Aimport java.util.concurrent.TimeUnit;%0Aimport java.util.function.BooleanSupplier
 ;%0Aim
@@ -1299,16 +1299,51 @@
 ectors;%0A
+import java.util.stream.IntStream;%0A
 import j
@@ -2042,16 +2042,934 @@
 ows, 1);
+%0A    private BatchIterator crossJoin = NestedLoopBatchIterator.crossJoin(%0A        RowsBatchIterator.newInstance(IntStream.range(0, 1000).mapToObj(Row1::new).collect(Collectors.toList()), 1),%0A        RowsBatchIterator.newInstance(IntStream.range(0, 10000).mapToObj(Row1::new).collect(Collectors.toList()), 1)%0A    );%0A%0A    private BatchIterator leftJoin = NestedLoopBatchIterator.leftJoin(%0A        RowsBatchIterator.newInstance(IntStream.range(0, 1000).mapToObj(Row1::new).collect(Collectors.toList()), 1),%0A        RowsBatchIterator.newInstance(IntStream.range(0, 10000).mapToObj(Row1::new).collect(Collectors.toList()), 1),%0A        columns -%3E new BooleanSupplier() %7B%0A%0A            Input%3C?%3E col1 = columns.get(0);%0A            Input%3C?%3E col2 = columns.get(1);%0A%0A            @Override%0A            public boolean getAsBoolean() %7B%0A                return Objects.equals(col1.value(), col2.value());%0A            %7D%0A        %7D%0A    );
 %0A%0A    pr
@@ -3970,32 +3970,32 @@
 e());%0A        %7D%0A
-
         skipping
@@ -4017,11 +4017,600 @@
 );%0A    %7D
+%0A%0A    @Benchmark%0A    public void measureConsumeNestedLoopJoin(Blackhole blackhole) throws Exception %7B%0A        final Input%3C?%3E input = crossJoin.rowData().get(0);%0A        while (crossJoin.moveNext()) %7B%0A            blackhole.consume(input.value());%0A        %7D%0A        crossJoin.moveToStart();%0A    %7D%0A%0A    @Benchmark%0A    public void measureConsumeNestedLoopLeftJoin(Blackhole blackhole) throws Exception %7B%0A        final Input%3C?%3E input = leftJoin.rowData().get(0);%0A        while (leftJoin.moveNext()) %7B%0A            blackhole.consume(input.value());%0A        %7D%0A        leftJoin.moveToStart();%0A    %7D
 %0A%7D%0A

Add NestedLoopBatchIterator benchmarks