Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Locking for Transactions and Increased Handling of Errors #520

Merged
merged 24 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
653bb78
added handling for various deadlock scenarios to handle error on para…
datomo Oct 4, 2024
70aae12
fixes for some deadlock scenarios, fix for error scenario
datomo Oct 7, 2024
f7ccf85
removed debug statements
datomo Oct 7, 2024
4f03dcb
fixed waiters problems with empty peak, cleaned up exceptions, no mor…
datomo Oct 7, 2024
c9bceca
Fix SelectTest
gartens Oct 7, 2024
ecdbbf8
fixed mongodb string values containing dollar signs
datomo Oct 7, 2024
1e01288
Merge branch 'better-locking' of github.com:polypheny/Polypheny-DB in…
datomo Oct 7, 2024
3213499
Remove superfluous try blocks
gartens Oct 7, 2024
b341b83
Switch to GenericRuntimeException and improve exception messages
gartens Oct 8, 2024
9ab474a
Do not log DeadlockExceptions in Prism interface
gartens Oct 8, 2024
3067775
fixed incorrect list.of call
datomo Oct 8, 2024
a291683
Use @SneakyThrows to avoid wrapping an exception
gartens Oct 8, 2024
17f165f
added comment and reformat warn
datomo Oct 8, 2024
46ce5c3
Merge branch 'better-locking' of https://github.com/polypheny/Polyphe…
datomo Oct 8, 2024
d1f5b32
fixes for tpcc and statistics
datomo Oct 9, 2024
dd12fad
hopefully finally fixed slow postgres and improved all jdbc stores
datomo Oct 17, 2024
5d1300c
Replace RuntimeException with GenericRuntimeException
gartens Oct 23, 2024
25874c5
Format
gartens Oct 23, 2024
35e5e30
Use cleanupWaiters like the other code paths
gartens Oct 23, 2024
7b4c449
changed triple in Lockmanager to dedicated record
datomo Oct 24, 2024
2a9c44a
Move LockInformation into LockManager
gartens Oct 24, 2024
040e43e
Remove superfluous parenthesis
gartens Oct 24, 2024
0640760
Remove unreachable code: .add always returns true
gartens Oct 29, 2024
fcfaa61
Improve formatting, optimize imports, update year in copyright
vogti Nov 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public MetadataDef<BuiltInMetadata.Collation> getDef() {

/**
* Catch-all implementation for {@link BuiltInMetadata.Collation#collations()}, invoked using reflection, for any relational expression not handled by a more specific method.
*
* <p>
* {@link org.polypheny.db.algebra.core.Union},
* {@link org.polypheny.db.algebra.core.Intersect},
* {@link Minus},
Expand Down Expand Up @@ -254,8 +254,7 @@ public static List<AlgCollation> project( AlgMetadataQuery mq, AlgNode input, Li
for ( Ord<RexNode> project : Ord.<RexNode>zip( projects ) ) {
if ( project.e instanceof RexIndexRef ) {
targets.put( ((RexIndexRef) project.e).getIndex(), project.i );
} else if ( project.e instanceof RexCall ) {
final RexCall call = (RexCall) project.e;
} else if ( project.e instanceof RexCall call ) {
final RexCallBinding binding = RexCallBinding.create( input.getCluster().getTypeFactory(), call, inputCollations );
targetsWithMonotonicity.put( project.i, call.getOperator().getMonotonicity( binding ) );
}
Expand Down Expand Up @@ -301,7 +300,7 @@ public static List<AlgCollation> project( AlgMetadataQuery mq, AlgNode input, Li

/**
* Helper method to determine a {@link Window}'s collation.
*
* <p>
* A Window projects the fields of its input first, followed by the output from each of its windows. Assuming (quite reasonably) that the implementation does not re-order its input rows,
* then any collations of its input are preserved.
*/
Expand All @@ -312,9 +311,9 @@ public static List<AlgCollation> window( AlgMetadataQuery mq, AlgNode input, Imm

/**
* Helper method to determine a {@link org.polypheny.db.algebra.core.Values}'s collation.
*
* <p>
* We actually under-report the collations. A Values with 0 or 1 rows - an edge case, but legitimate and very common - is ordered by every permutation of every subset of the columns.
*
* <p>
* So, our algorithm aims to:
* <ul>
* <li>produce at most N collations (where N is the number of columns);</li>
Expand Down Expand Up @@ -386,7 +385,7 @@ public int compare( List<RexLiteral> o1, List<RexLiteral> o2 ) {

/**
* Helper method to determine a {@link Join}'s collation assuming that it uses a merge-join algorithm.
*
* <p>
* If the inputs are sorted on other keys <em>in addition to</em> the join key, the result preserves those collations too.
*/
public static List<AlgCollation> mergeJoin( AlgMetadataQuery mq, AlgNode left, AlgNode right, ImmutableList<Integer> leftKeys, ImmutableList<Integer> rightKeys ) {
Expand Down Expand Up @@ -436,25 +435,22 @@ public static List<AlgCollation> enumerableSemiJoin( AlgMetadataQuery mq, AlgNod

private static List<AlgCollation> enumerableJoin0( AlgMetadataQuery mq, AlgNode left, AlgNode right, JoinAlgType joinType ) {
// The current implementation can preserve the sort order of the left input if one of the following conditions hold:
// (i) join type is INNER or LEFT;
// (ii) RelCollation always orders nulls last.
final ImmutableList<AlgCollation> leftCollations = mq.collations( left );
switch ( joinType ) {
case INNER:
case LEFT:
return leftCollations;
case RIGHT:
case FULL:
return switch ( joinType ) {
// (i) join type is INNER or LEFT;
case INNER, LEFT -> leftCollations;
// (ii) RelCollation always orders nulls last.
case RIGHT, FULL -> {
for ( AlgCollation collation : leftCollations ) {
for ( AlgFieldCollation field : collation.getFieldCollations() ) {
if ( !(AlgFieldCollation.NullDirection.LAST == field.nullDirection) ) {
return ImmutableList.of();
yield ImmutableList.of();
}
}
}
return leftCollations;
}
return ImmutableList.of();
yield leftCollations;
}
};
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,15 @@ public Set<AlgColumnOrigin> getColumnOrigins( Project alg, final AlgMetadataQuer
final AlgNode input = alg.getInput();
RexNode rexNode = alg.getProjects().get( iOutputColumn );

if ( rexNode instanceof RexIndexRef ) {
if ( rexNode instanceof RexIndexRef inputRef ) {
// Direct reference: no derivation added.
RexIndexRef inputRef = (RexIndexRef) rexNode;
return mq.getColumnOrigins( input, inputRef.getIndex() );
}

// Anything else is a derivation, possibly from multiple columns.
final Set<AlgColumnOrigin> set = new HashSet<>();
RexVisitor visitor =
new RexVisitorImpl<Void>( true ) {
RexVisitor<Void> visitor =
new RexVisitorImpl<>( true ) {
@Override
public Void visitIndexRef( RexIndexRef inputRef ) {
Set<AlgColumnOrigin> inputSet = mq.getColumnOrigins( input, inputRef.getIndex() );
Expand Down Expand Up @@ -185,7 +184,7 @@ public Set<AlgColumnOrigin> getColumnOrigins( RelTableFunctionScan alg, AlgMetad
final Set<AlgColumnOrigin> set = new HashSet<>();
Set<AlgColumnMapping> mappings = alg.getColumnMappings();
if ( mappings == null ) {
if ( alg.getInputs().size() > 0 ) {
if ( !alg.getInputs().isEmpty() ) {
// This is a non-leaf transformation: say we don't know about origins, because there are probably columns below.
return null;
} else {
Expand Down Expand Up @@ -215,7 +214,7 @@ public Set<AlgColumnOrigin> getColumnOrigins( RelTableFunctionScan alg, AlgMetad
// Catch-all rule when none of the others apply.
public Set<AlgColumnOrigin> getColumnOrigins( AlgNode alg, AlgMetadataQuery mq, int iOutputColumn ) {
// NOTE jvs 28-Mar-2006: We may get this wrong for a physical table expression which supports projections. In that case, it's up to the plugin writer to override with the correct information.
if ( alg.getInputs().size() > 0 ) {
if ( !alg.getInputs().isEmpty() ) {
// No generic logic available for non-leaf rels.
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 The Polypheny Project
* Copyright 2019-2024 The Polypheny Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -40,20 +40,20 @@


/**
* RelMetadataProvider defines an interface for obtaining metadata about relational expressions. This interface is weakly-typed and is not intended to be called directly in most contexts;
* {@link AlgMetadataProvider} defines an interface for obtaining metadata about algebra expressions. This interface is weakly-typed and is not intended to be called directly in most contexts;
* instead, use a strongly-typed facade such as {@link AlgMetadataQuery}.
*
* <p>
* For background and motivation, see <a href="http://wiki.eigenbase.org/RelationalExpressionMetadata">wiki</a>.
*
* <p>
* If your provider is not a singleton, we recommend that you implement {@link Object#equals(Object)} and {@link Object#hashCode()} methods. This makes the cache of {@link JaninoRelMetadataProvider} more effective.
*/
public interface AlgMetadataProvider {

/**
* Retrieves metadata of a particular type and for a particular sub-class of relational expression.
*
* The object returned is a function. It can be applied to a relational expression of the given type to create a metadata object.
*
* <p>
* The object returned is a function. It can be applied to an algebra expression of the given type to create a metadata object.
* <p>
* For example, you might call
*
* <blockquote><pre>
Expand All @@ -65,7 +65,7 @@ public interface AlgMetadataProvider {
* Double d = selectivity.selectivity(predicate);
* </pre></blockquote>
*
* @param algClass Type of relational expression
* @param algClass Type of algebra expression
* @param metadataClass Type of metadata
* @return Function that will field a metadata instance; or null if this provider cannot supply metadata of this type
*/
Expand All @@ -74,4 +74,3 @@ public interface AlgMetadataProvider {
<M extends Metadata> Multimap<Method, MetadataHandler<M>> handlers( MetadataDef<M> def );

}

Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
import org.polypheny.db.algebra.logical.relational.LogicalWindow;
import org.polypheny.db.algebra.stream.LogicalChi;
import org.polypheny.db.algebra.stream.LogicalDelta;
import org.polypheny.db.catalog.exceptions.GenericRuntimeException;
import org.polypheny.db.config.RuntimeConfig;
import org.polypheny.db.interpreter.JaninoRexCompiler;
import org.polypheny.db.plan.hep.HepAlgVertex;
Expand Down Expand Up @@ -458,7 +459,7 @@ private static <M extends Metadata> MetadataHandler<M> load3( MetadataDef<M> def
try {
return compile( name, buff.toString(), def, argList );
} catch ( CompileException | IOException e ) {
throw new RuntimeException( "Error compiling:\n" + buff, e );
throw new GenericRuntimeException( "Error compiling:\n" + buff, e );
}
}

Expand Down Expand Up @@ -551,7 +552,7 @@ static <M extends Metadata> MetadataHandler<M> compile( String className, String
constructor = compiler.getClassLoader().loadClass( className ).getDeclaredConstructors()[0];
o = constructor.newInstance( argList.toArray() );
} catch ( InstantiationException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e ) {
throw new RuntimeException( e );
throw new GenericRuntimeException( e );
}
return def.handlerClass.cast( o );
}
Expand All @@ -564,7 +565,7 @@ synchronized <M extends Metadata, H extends MetadataHandler<M>> H create( Metada
return (H) HANDLERS.get( key );
} catch ( UncheckedExecutionException | ExecutionException e ) {
Util.throwIfUnchecked( e.getCause() );
throw new RuntimeException( e.getCause() );
throw new GenericRuntimeException( e.getCause() );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ public enum RuntimeConfig {
LOCKING_MAX_TIMEOUT_SECONDS(
"runtime/maxTimeout",
"How long a transactions should wait for a lock until it is aborted",
30,
90,
ConfigType.INTEGER );


Expand Down
25 changes: 12 additions & 13 deletions core/src/main/java/org/polypheny/db/languages/LanguageManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import org.polypheny.db.processing.QueryContext.ParsedQueryContext;
import org.polypheny.db.transaction.Statement;
import org.polypheny.db.transaction.Transaction;
import org.polypheny.db.transaction.TransactionException;
import org.polypheny.db.util.DeadlockException;
import org.polypheny.db.util.Pair;

@Slf4j
Expand Down Expand Up @@ -111,11 +111,11 @@ public List<ImplementationContext> anyPrepareQuery( QueryContext context, Statem

parsedQueries = context.getLanguage().parser().apply( context );
} catch ( Throwable e ) {
log.warn( "Error on preparing query: {}", e.getMessage() );
if ( transaction.isAnalyze() ) {
transaction.getQueryAnalyzer().attachStacktrace( e );
}
cancelTransaction( transaction );
cancelTransaction( transaction, String.format( "Error on preparing query: %s", e.getMessage() ) );
context.removeTransaction( transaction );
return List.of( ImplementationContext.ofError( e, ParsedQueryContext.fromQuery( context.getQuery(), null, context ), statement ) );
}

Expand Down Expand Up @@ -200,11 +200,15 @@ public List<ImplementationContext> anyPrepareQuery( QueryContext context, Statem
implementationContexts.add( new ImplementationContext( implementation, parsed, statement, null ) );

} catch ( Throwable e ) {
log.warn( "Caught exception: ", e ); // TODO: This should not log in all cases, at least not with stacktrace
if ( !(e instanceof DeadlockException) ) {
// we only log unexpected cases with stacktrace
log.warn( "Caught exception: ", e );
}

if ( transaction.isAnalyze() ) {
transaction.getQueryAnalyzer().attachStacktrace( e );
}
cancelTransaction( transaction );
cancelTransaction( transaction, e.getMessage() );
implementationContexts.add( ImplementationContext.ofError( e, parsed, statement ) );
return implementationContexts;
}
Expand All @@ -224,14 +228,9 @@ private static List<ImplementationContext> handleParseException( Statement state
}


private static void cancelTransaction( @Nullable Transaction transaction ) {
private static void cancelTransaction( @Nullable Transaction transaction, @Nullable String reason ) {
if ( transaction != null && transaction.isActive() ) {
try {
transaction.rollback();
} catch ( TransactionException ex ) {
// Ignore
log.warn( "Error during rollback: " + ex.getMessage() );
}
transaction.rollback( reason );
}
}

Expand All @@ -251,7 +250,7 @@ public List<ExecutedContext> anyQuery( QueryContext context ) {
if ( transaction.isAnalyze() && implementation.getException().isEmpty() ) {
transaction.getQueryAnalyzer().attachStacktrace( e );
}
cancelTransaction( transaction );
cancelTransaction( transaction, e.getMessage() );

executedContexts.add( ExecutedContext.ofError( e, implementation, null ) );
return executedContexts;
Expand Down
20 changes: 10 additions & 10 deletions core/src/main/java/org/polypheny/db/plan/AlgTraitSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private AlgTraitSet( Cache cache, AlgTrait<?>[] traits ) {

/**
* Creates an empty trait set.
*
* <p>
* It has a new cache, which will be shared by any trait set created from it. Thus each empty trait set is the start of a new ancestral line.
*/
public static AlgTraitSet createEmpty() {
Expand Down Expand Up @@ -149,7 +149,7 @@ public <T extends AlgTrait<?>> T getTrait( AlgTraitDef<T> traitDef ) {

/**
* Retrieves a list of traits of the given type from the set.
*
* <p>
* Only valid for traits that support multiple entries. (E.g. collation.)
*
* @param traitDef the type of RelTrait to retrieve
Expand Down Expand Up @@ -187,7 +187,7 @@ public AlgTraitSet replace( int index, AlgTrait<?> trait ) {

/**
* Returns a trait set consisting of the current set plus a new trait.
*
* <p>
* If the set does not contain a trait of the same {@link AlgTraitDef}, the trait is ignored, and this trait set is returned.
*
* @param trait the new trait
Expand All @@ -212,7 +212,7 @@ public AlgTraitSet replace( AlgTrait<?> trait ) {

/**
* Returns whether an element occurs within an array.
*
* <p>
* Uses {@code ==}, not {@link #equals}. Nulls are allowed.
*/
private static <T> boolean containsShallow( T[] ts, AlgTrait<?> seek ) {
Expand All @@ -227,7 +227,7 @@ private static <T> boolean containsShallow( T[] ts, AlgTrait<?> seek ) {

/**
* Replaces the trait(s) of a given type with a list of traits of the same type.
*
* <p>
* The list must not be empty, and all traits must be of the same type.
*/
public <T extends AlgMultipleTrait<?>> AlgTraitSet replace( List<T> traits ) {
Expand All @@ -239,7 +239,7 @@ public <T extends AlgMultipleTrait<?>> AlgTraitSet replace( List<T> traits ) {

/**
* Replaces the trait(s) of a given type with a list of traits of the same type.
*
* <p>
* The list must not be empty, and all traits must be of the same type.
*/
public <T extends AlgMultipleTrait<?>> AlgTraitSet replace( AlgTraitDef<T> def, List<T> traits ) {
Expand Down Expand Up @@ -286,7 +286,7 @@ public int size() {

/**
* Converts a trait to canonical form.
*
* <p>
* After canonization, t1.equals(t2) if and only if t1 == t2.
*
* @param trait Trait
Expand Down Expand Up @@ -329,11 +329,11 @@ public int hashCode() {

/**
* Returns whether this trait set satisfies another trait set.
*
* <p>
* For that to happen, each trait satisfies the corresponding trait in the other set. In particular, each trait set satisfies itself, because each trait subsumes itself.
*
* <p>
* Intuitively, if a relational expression is needed that has trait set S (A, B), and trait set S1 (A1, B1) subsumes S, then any relational expression R in S1 meets that need.
*
* <p>
* For example, if we need a relational expression that has trait set S = {enumerable convention, sorted on [C1 asc]}, and R has {enumerable convention, sorted on [C3], [C1, C2]}.
* R has two sort keys, but one them [C1, C2] satisfies S [C1], and that is enough.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@


/**
* VolcanoRelMetadataProvider implements the {@link AlgMetadataProvider} interface by combining metadata from the rels making up an equivalence class.
* {@link VolcanoAlgMetadataProvider} implements the {@link AlgMetadataProvider} interface by combining metadata from the alg making up an equivalence class.
*/
public class VolcanoAlgMetadataProvider implements AlgMetadataProvider {

Expand Down Expand Up @@ -87,7 +87,7 @@ public <M extends Metadata> UnboundMetadata<M> apply( Class<? extends AlgNode> a
}
}

// Otherwise, try rels in same logical equivalence class to see if any of them have a good answer. We use the full logical equivalence class rather than just the subset because
// Otherwise, try algs in same logical equivalence class to see if any of them have a good answer. We use the full logical equivalence class rather than just the subset because
// many metadata providers only know about logical metadata.

// Equivalence classes can get tangled up in interesting ways, so avoid an infinite loop. REVIEW: There's a chance this will cause us to fail on metadata queries which invoke other queries,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.polypheny.db.algebra.AlgRoot;
import org.polypheny.db.algebra.constant.Kind;
import org.polypheny.db.algebra.type.AlgDataType;
import org.polypheny.db.catalog.exceptions.GenericRuntimeException;
import org.polypheny.db.languages.QueryParameters;
import org.polypheny.db.nodes.ExecutableStatement;
import org.polypheny.db.nodes.Node;
Expand Down Expand Up @@ -52,9 +51,7 @@ public PolyImplementation prepareDdl( Statement statement, ExecutableStatement n
// Execute statement
return getImplementation( statement, node, context );
} catch ( DeadlockException e ) {
throw new GenericRuntimeException( "Exception while acquiring global schema lock", e );
} catch ( TransactionException e ) {
throw new GenericRuntimeException( e );
throw new DeadlockException( e.getMessage() + " Exception while acquiring global schema lock" );
} finally {
// Release lock
unlock( statement );
Expand Down
Loading