<commit_before>/*
 * Copyright (c) 2002-2015 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.neo4j.cypher;

import org.junit.Rule;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

import org.neo4j.cypher.internal.compiler.v2_2.CypherCacheHitMonitor;
import org.neo4j.cypher.internal.compiler.v2_2.ast.Statement;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction;
import org.neo4j.kernel.monitoring.Monitors;
import org.neo4j.test.DatabaseRule;
import org.neo4j.test.ImpermanentDatabaseRule;

import static java.util.Collections.singletonMap;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;

public class QueryInvalidationIT
{
    private static final int USERS = 10;
    private static final int CONNECTIONS = 100;

    @Rule
    public final DatabaseRule db = new ImpermanentDatabaseRule();

    @Test
    public void shouldRePlanAfterDataChangesFromAnEmptyDatabase() throws Exception
    {
        // GIVEN
        TestMonitor monitor = new TestMonitor();
        db.resolveDependency( Monitors.class ).addMonitorListener( monitor );
        // - setup schema -
        createIndex();
        // - execute the query without the existence data -
        executeDistantFriendsCountQuery( USERS );

        long replanTime = System.currentTimeMillis() + 1_800;

        // - create data -
        createData( 0, USERS, CONNECTIONS );

        // - after the query TTL has expired -
        while ( System.currentTimeMillis() < replanTime )
        {
            Thread.sleep( 100 );
        }

        // WHEN
        monitor.reset();
        // - execute the query again -
        executeDistantFriendsCountQuery( USERS );

        // THEN
        assertEquals( "Query should have been replanned.", 1, monitor.discards.get() );
    }

    @Test
    public void shouldRePlanAfterDataChangesFromAPopulatedDatabase() throws Exception
    {
        // GIVEN
        TestMonitor monitor = new TestMonitor();
        db.resolveDependency( Monitors.class ).addMonitorListener( monitor );
        // - setup schema -
        createIndex();
        //create some data
        createData( 0, USERS, CONNECTIONS );
        executeDistantFriendsCountQuery( USERS );

        long replanTime = System.currentTimeMillis() + 1_800;

        //create more date
        createData( USERS, USERS, 2 * CONNECTIONS );

        // - after the query TTL has expired -
        while ( System.currentTimeMillis() < replanTime )
        {
            Thread.sleep( 100 );
        }

        // WHEN
        monitor.reset();
        // - execute the query again -
        executeDistantFriendsCountQuery( USERS );

        // THEN
        assertEquals( "Query should have been replanned.", 1, monitor.discards.get() );
    }

    private void createIndex()
    {
        try ( Transaction tx = db.beginTx() )
        {
            db.schema().indexFor( DynamicLabel.label( "User" ) ).on( "userId" ).create();
            tx.success();
        }
        try ( Transaction tx = db.beginTx() )
        {
            db.schema().awaitIndexesOnline( 10, SECONDS );
            tx.success();
        }
    }

    private void createData( long startingUserId, int numUsers, int numConnections )
    {
        for ( long userId = startingUserId; userId < numUsers + startingUserId; userId++ )
        {<commit_msg>Fix indeterministic test case in QueryInvalidationIT<commit_after>/*
 * Copyright (c) 2002-2015 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.neo4j.cypher;

import org.junit.Rule;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

import org.neo4j.cypher.internal.compiler.v2_2.CypherCacheHitMonitor;
import org.neo4j.cypher.internal.compiler.v2_2.ast.Statement;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.monitoring.Monitors;
import org.neo4j.test.DatabaseRule;
import org.neo4j.test.ImpermanentDatabaseRule;

import static java.util.Collections.singletonMap;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class QueryInvalidationIT
{
    private static final int USERS = 10;
    private static final int CONNECTIONS = 100;

    @Rule
    public final DatabaseRule db = new ImpermanentDatabaseRule()
    {
        @Override
        protected void configure( GraphDatabaseBuilder builder )
        {
            super.configure( builder );
            builder.setConfig( GraphDatabaseSettings.query_statistics_divergence_threshold, "0.5" );
            builder.setConfig( GraphDatabaseSettings.cypher_min_replan_interval, "1s" );
        }
    };

    @Test
    public void shouldRePlanAfterDataChangesFromAnEmptyDatabase() throws Exception
    {
        // GIVEN
        TestMonitor monitor = new TestMonitor();
        db.resolveDependency( Monitors.class ).addMonitorListener( monitor );
        // - setup schema -
        createIndex();
        // - execute the query without the existence data -
        executeDistantFriendsCountQuery( USERS );

        long replanTime = System.currentTimeMillis() + 1_800;

        // - create data -
        createData( 0, USERS, CONNECTIONS );

        // - after the query TTL has expired -
        while ( System.currentTimeMillis() < replanTime )
        {
            Thread.sleep( 100 );
        }

        // WHEN
        monitor.reset();
        // - execute the query again -
        executeDistantFriendsCountQuery( USERS );

        // THEN
        assertEquals( "Query should have been replanned.", 1, monitor.discards.get() );
    }

    @Test
    public void shouldRePlanAfterDataChangesFromAPopulatedDatabase() throws Exception
    {
        // GIVEN
        Config config = db.getConfigCopy();
        double divergenceThreshold = config.get( GraphDatabaseSettings.query_statistics_divergence_threshold );
        long replanInterval = config.get( GraphDatabaseSettings.cypher_min_replan_interval );

        TestMonitor monitor = new TestMonitor();
        db.resolveDependency( Monitors.class ).addMonitorListener( monitor );
        // - setup schema -
        createIndex();
        //create some data
        createData( 0, USERS, CONNECTIONS );
        executeDistantFriendsCountQuery( USERS );

        long replanTime = System.currentTimeMillis() + replanInterval;

        assertTrue( "Test does not work with edge setting for query_statistics_divergence_threshold: " + divergenceThreshold,
                divergenceThreshold > 0.0 && divergenceThreshold < 1.0 );

        int usersToCreate = ((int) (Math.ceil( ((double) USERS) / (1.0 - divergenceThreshold) ))) - USERS + 1;

        //create more data
        createData( USERS, usersToCreate, CONNECTIONS );

        // - after the query TTL has expired -
        while ( System.currentTimeMillis() <= replanTime )
        {
            Thread.sleep( 100 );
        }

        // WHEN
        monitor.reset();
        // - execute the query again -
        executeDistantFriendsCountQuery( USERS );

        // THEN
        assertEquals( "Query should have been replanned.", 1, monitor.discards.get() );
    }

    private void createIndex()
    {
        try ( Transaction tx = db.beginTx() )
        {
            db.schema().indexFor( DynamicLabel.label( "User" ) ).on( "userId" ).create();
            tx.success();
        }
        try ( Transaction tx = db.beginTx() )
        {
            db.schema().awaitIndexesOnline( 10, SECONDS );
            tx.success();
        }
    }

    private void createData( long startingUserId, int numUsers, int numConnections )
    {
        for ( long userId = startingUserId; userId < numUsers + startingUserId; userId++ )
        {
{'fraction_non_alphanumeric': 0.09375648205766439, 'fraction_numerical': 0.01120099564405725, 'mean_word_length': 2.669330289193303, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 6, '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': '2896004', 'n_tokens_mistral': 2744, 'n_tokens_neox': 2617, 'n_words': 763}