Skip to content

Commit

Permalink
Changed ExecutingQueryEntry to use the Null pattern
Browse files Browse the repository at this point in the history
Avoids null checking in KernelStatement
  • Loading branch information
systay committed Sep 6, 2016
1 parent 597a683 commit bde396a
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 81 deletions.

This file was deleted.

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2002-2016 "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.kernel.impl.api;

import java.util.stream.Stream;

import org.neo4j.kernel.api.ExecutingQuery;

interface ExecutingQueryList
{
Stream<ExecutingQuery> queries();

ExecutingQueryList push( ExecutingQuery newExecutingQuery );

ExecutingQueryList remove( ExecutingQuery executingQuery );

ExecutingQueryList EMPTY = new Empty();

class Entry implements ExecutingQueryList
{
final ExecutingQuery query;
final ExecutingQueryList next;

Entry( ExecutingQuery query, ExecutingQueryList next )
{
this.query = query;
this.next = next;
}

@Override
public Stream<ExecutingQuery> queries()
{
Stream.Builder<ExecutingQuery> builder = Stream.builder();
ExecutingQueryList entry = this;
while ( entry != EMPTY )
{
Entry current = (Entry) entry;
builder.accept( current.query );
entry = current.next;
}
return builder.build();
}

@Override
public ExecutingQueryList push( ExecutingQuery newExecutingQuery )
{
assert( newExecutingQuery.queryId() > query.queryId() );
return new Entry( newExecutingQuery, this );
}

@Override
public ExecutingQueryList remove( ExecutingQuery executingQuery )
{
if ( executingQuery.equals( query ) )
{
return next;
}
else
{
return next == EMPTY ? EMPTY : new Entry( query, next.remove( executingQuery ) );
}
}
}

class Empty implements ExecutingQueryList
{
@Override
public Stream<ExecutingQuery> queries()
{
return Stream.empty();
}

@Override
public ExecutingQueryList push( ExecutingQuery newExecutingQuery )
{
return new Entry(newExecutingQuery, this);
}

@Override
public ExecutingQueryList remove( ExecutingQuery executingQuery )
{
return this;
}
}
}
Expand Up @@ -66,7 +66,7 @@ public class KernelStatement implements TxStateHolder, Statement
private final OperationsFacade facade;
private StatementLocks statementLocks;
private int referenceCount;
private volatile ExecutingQueryEntry executingQueryListHead;
private volatile ExecutingQueryList executingQueryList;

public KernelStatement(
KernelTransactionImplementation transaction,
Expand All @@ -80,7 +80,7 @@ public KernelStatement(
this.txStateHolder = txStateHolder;
this.storeStatement = storeStatement;
this.facade = new OperationsFacade( transaction, this, operations, procedures );
this.executingQueryListHead = null;
this.executingQueryList = ExecutingQueryList.EMPTY;
}

@Override
Expand Down Expand Up @@ -214,19 +214,17 @@ final String authSubjectName()

final Stream<ExecutingQuery> executingQueries()
{
return executingQueryListHead == null ? Stream.empty() : executingQueryListHead.queries();
return executingQueryList.queries();
}

final void startQueryExecution( ExecutingQuery query )
{
this.executingQueryListHead =
executingQueryListHead == null ?
new ExecutingQueryEntry( query, null ) : executingQueryListHead.push( query );
this.executingQueryList = executingQueryList.push( query );
}

final void stopQueryExecution( ExecutingQuery executingQuery )
{
this.executingQueryListHead = executingQueryListHead.remove( executingQuery );
this.executingQueryList = executingQueryList.remove( executingQuery );
}

/* only public for tests */ public final StorageStatement getStoreStatement()
Expand All @@ -238,6 +236,6 @@ private void cleanupResources()
{
// closing is done by KTI
storeStatement.release();
executingQueryListHead = null;
executingQueryList = ExecutingQueryList.EMPTY;
}
}
Expand Up @@ -24,15 +24,10 @@

import org.neo4j.kernel.api.ExecutingQuery;
import org.neo4j.kernel.impl.api.KernelStatement;
import org.neo4j.kernel.impl.query.QuerySession;
import org.neo4j.kernel.impl.query.TransactionalContext;

public interface MetaStatementOperations
{
Stream<ExecutingQuery> executingQueries( KernelStatement statement );
ExecutingQuery startQueryExecution( KernelStatement statement, String queryText, Map<String, Object> queryParameters );
void stopQueryExecution( KernelStatement statement, ExecutingQuery executingQuery );

QuerySession.MetadataKey<ExecutingQuery> METADATA_KEY =
new QuerySession.MetadataKey<>( ExecutingQuery.class, "executing-query" );
}
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2002-2016 "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.kernel.impl.api;

import org.junit.Test;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import org.neo4j.kernel.api.ExecutingQuery;

import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;

public class ExecutingQueryListTest
{
@Test
public void removingTheLastQueryReturnsAnEmptyList()
{
// Given
ExecutingQuery aQuery = new ExecutingQuery( 1, "me", "query", Collections.emptyMap() );
ExecutingQueryList list = ExecutingQueryList.EMPTY.push( aQuery );

// When
ExecutingQueryList result = list.remove( aQuery );

// Then
assertThat( result, equalTo( ExecutingQueryList.EMPTY ) );
}

@Test
public void addingQueriesKeepsInsertOrder()
{
// Given
ExecutingQuery query1 = new ExecutingQuery( 1, "me", "query1", Collections.emptyMap() );
ExecutingQuery query2 = new ExecutingQuery( 2, "me", "query2", Collections.emptyMap() );
ExecutingQuery query3 = new ExecutingQuery( 3, "me", "query3", Collections.emptyMap() );
ExecutingQuery query4 = new ExecutingQuery( 4, "me", "query4", Collections.emptyMap() );
ExecutingQuery query5 = new ExecutingQuery( 5, "me", "query5", Collections.emptyMap() );

ExecutingQueryList list = ExecutingQueryList.EMPTY
.push( query1 )
.push( query2 )
.push( query3 )
.push( query4 )
.push( query5 );

// When
List<ExecutingQuery> result = list.queries().collect( Collectors.toList() );

// Then
assertThat( result, equalTo( asList( query1, query2, query3, query4, query5 ) ) );
}

@Test
public void removingQueryInTheMiddleKeepsOrder()
{
// Given
ExecutingQuery query1 = new ExecutingQuery( 1, "me", "query1", Collections.emptyMap() );
ExecutingQuery query2 = new ExecutingQuery( 2, "me", "query2", Collections.emptyMap() );
ExecutingQuery query3 = new ExecutingQuery( 3, "me", "query3", Collections.emptyMap() );
ExecutingQuery query4 = new ExecutingQuery( 4, "me", "query4", Collections.emptyMap() );
ExecutingQuery query5 = new ExecutingQuery( 5, "me", "query5", Collections.emptyMap() );

ExecutingQueryList list = ExecutingQueryList.EMPTY
.push( query1 )
.push( query2 )
.push( query3 )
.push( query4 )
.push( query5 );

// When
list.remove( query3 );
List<ExecutingQuery> result = list.queries().collect( Collectors.toList() );

// Then
assertThat( result, equalTo( asList( query1, query2, query4, query5 ) ) );
}
}
Expand Up @@ -30,9 +30,7 @@

import static junit.framework.TestCase.fail;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertTrue;

public class ThreadedTransactionCreate<S>
{
Expand Down

0 comments on commit bde396a

Please sign in to comment.