From 68d7a78b03373f4837676f8c261684d48d10d5e3 Mon Sep 17 00:00:00 2001 From: Ulrich Kramer Date: Thu, 19 Dec 2024 06:33:12 +0100 Subject: [PATCH] [CALCITE-6728] Introduce new methods to lookup tables and schemas inside schemas --- .../calcite/jdbc/CachingCalciteSchema.java | 12 +++- .../apache/calcite/jdbc/CalciteSchema.java | 62 +++++++++---------- .../calcite/schema/lookup/LazyReference.java | 43 +++++++++++++ 3 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 core/src/main/java/org/apache/calcite/schema/lookup/LazyReference.java diff --git a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java index fb29b4dcbd5..3e94ee5cd05 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java @@ -37,6 +37,7 @@ import java.util.Collection; import java.util.List; +import java.util.concurrent.ConcurrentLinkedDeque; import static org.apache.calcite.linq4j.Nullness.castNonNull; @@ -45,7 +46,7 @@ * functions and sub-schemas. */ class CachingCalciteSchema extends CalciteSchema { - private final ImmutableList> caches; + private final ConcurrentLinkedDeque> caches = new ConcurrentLinkedDeque<>(); private final Cached implicitFunctionCache; private final Cached implicitTypeCache; @@ -71,8 +72,7 @@ private CachingCalciteSchema(@Nullable CalciteSchema parent, Schema schema, @Nullable List> path, LookupDecorator lookupDecorator) { super(parent, schema, name, subSchemaMap, tableMap, latticeMap, typeMap, - functionMap, functionNames, nullaryFunctionMap, path, lookupDecorator); - this.caches = lookupDecorator.cacheBuilder.build(); + functionMap, functionNames, nullaryFunctionMap, path); this.implicitFunctionCache = new AbstractCached() { @Override public NameSet build() { @@ -107,6 +107,12 @@ private CachingCalciteSchema(@Nullable CalciteSchema parent, Schema schema, return new CachingCalciteSchema(this, schema, name); } + @Override protected Lookup decorateLookup(Lookup lookup) { + CachedLookup cachedLookup = new CachedLookup<>(lookup); + caches.add(cachedLookup); + return cachedLookup; + } + /** Adds a child schema of this schema. */ @Override public CalciteSchema add(String name, Schema schema) { final CalciteSchema calciteSchema = diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java index 0cf4ca4c2e0..cf32ab89b6f 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java @@ -17,7 +17,6 @@ package org.apache.calcite.jdbc; import org.apache.calcite.linq4j.function.Experimental; -import org.apache.calcite.linq4j.function.Function1; import org.apache.calcite.linq4j.tree.Expression; import org.apache.calcite.materialize.Lattice; import org.apache.calcite.rel.type.RelProtoDataType; @@ -30,6 +29,7 @@ import org.apache.calcite.schema.Wrapper; import org.apache.calcite.schema.impl.MaterializedViewTable; import org.apache.calcite.schema.impl.StarTable; +import org.apache.calcite.schema.lookup.LazyReference; import org.apache.calcite.schema.lookup.LikePattern; import org.apache.calcite.schema.lookup.Lookup; import org.apache.calcite.schema.lookup.Named; @@ -69,17 +69,16 @@ public abstract class CalciteSchema { /** Tables explicitly defined in this schema. Does not include tables in * {@link #schema}. */ protected final NameMap tableMap; - private final Lookup tables; + private final LazyReference> tables = new LazyReference<>(); protected final NameMultimap functionMap; protected final NameMap typeMap; protected final NameMap latticeMap; protected final NameSet functionNames; protected final NameMap nullaryFunctionMap; protected final NameMap subSchemaMap; - private final Lookup subSchemas; + private final LazyReference> subSchemas = new LazyReference<>(); private @Nullable List> path; - protected CalciteSchema(@Nullable CalciteSchema parent, Schema schema, String name, @Nullable NameMap subSchemaMap, @@ -90,21 +89,6 @@ protected CalciteSchema(@Nullable CalciteSchema parent, Schema schema, @Nullable NameSet functionNames, @Nullable NameMap nullaryFunctionMap, @Nullable List> path) { - this(parent, schema, name, subSchemaMap, tableMap, latticeMap, typeMap, functionMap, - functionNames, nullaryFunctionMap, path, l -> l); - } - - protected CalciteSchema(@Nullable CalciteSchema parent, Schema schema, - String name, - @Nullable NameMap subSchemaMap, - @Nullable NameMap tableMap, - @Nullable NameMap latticeMap, - @Nullable NameMap typeMap, - @Nullable NameMultimap functionMap, - @Nullable NameSet functionNames, - @Nullable NameMap nullaryFunctionMap, - @Nullable List> path, - Function1, Lookup> lookupDecorator) { this.parent = parent; this.schema = schema; this.name = name; @@ -129,14 +113,26 @@ protected CalciteSchema(@Nullable CalciteSchema parent, Schema schema, this.typeMap = typeMap; } this.path = path; - this.tables = - Lookup.concat(Lookup.of(this.tableMap), - (Lookup) lookupDecorator.apply( - schema.tables().map((s, n) -> tableEntry(n, s)))); - this.subSchemas = - Lookup.concat(Lookup.of(this.subSchemaMap), - (Lookup) lookupDecorator.apply( - schema.subSchemas().map((s, n) -> createSubSchema(s, n)))); + } + + public Lookup tables() { + return this.tables.getOrCompute(() -> + Lookup.concat( + Lookup.of(this.tableMap), + decorateLookup(schema.tables().map((s, n) -> tableEntry(n, s))))); + + } + + public Lookup subSchemas() { + return subSchemas.getOrCompute(() -> + Lookup.concat( + Lookup.of(this.subSchemaMap), + decorateLookup(schema.subSchemas().map((s, n) -> createSubSchema(s, n))))); + } + + /** The derived class is able to decorate the lookup. */ + protected Lookup decorateLookup(Lookup lookup) { + return lookup; } /** Creates a sub-schema with a given name that is defined implicitly. */ @@ -265,8 +261,8 @@ public List path(@Nullable String name) { public final @Nullable CalciteSchema getSubSchema(String schemaName, boolean caseSensitive) { return caseSensitive - ? subSchemas.get(schemaName) - : Named.entityOrNull(subSchemas.getIgnoreCase(schemaName)); + ? subSchemas().get(schemaName) + : Named.entityOrNull(subSchemas().getIgnoreCase(schemaName)); } /** Adds a child schema of this schema. */ @@ -284,7 +280,7 @@ public List path(@Nullable String name) { /** Returns a table with the given name. Does not look for views. */ public final @Nullable TableEntry getTable(String tableName, boolean caseSensitive) { - return Lookup.get(tables, tableName, caseSensitive); + return Lookup.get(tables(), tableName, caseSensitive); } public String getName() { @@ -345,7 +341,7 @@ public final Set getTableNames() { /** Returns the set of filtered table names. Includes implicit and explicit tables * and functions with zero parameters. */ public final Set getTableNames(LikePattern pattern) { - return tables.getNames(pattern); + return tables().getNames(pattern); } /** Returns the set of all types names. */ @@ -653,11 +649,11 @@ CalciteSchema calciteSchema() { } @Override public Lookup tables() { - return CalciteSchema.this.tables.map((table, name) -> table.getTable()); + return CalciteSchema.this.tables().map((table, name) -> table.getTable()); } @Override public Lookup subSchemas() { - return CalciteSchema.this.subSchemas.map((schema, name) -> schema.plus()); + return CalciteSchema.this.subSchemas().map((schema, name) -> schema.plus()); } @Override public @Nullable Table getTable(String name) { diff --git a/core/src/main/java/org/apache/calcite/schema/lookup/LazyReference.java b/core/src/main/java/org/apache/calcite/schema/lookup/LazyReference.java new file mode 100644 index 00000000000..dd53415d34b --- /dev/null +++ b/core/src/main/java/org/apache/calcite/schema/lookup/LazyReference.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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. + */ +package org.apache.calcite.schema.lookup; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +/** + * This class can be used to lazily initialize an object. + * + * @param Element Type + */ +public class LazyReference { + + private final AtomicReference value = new AtomicReference<>(); + + public T getOrCompute(Supplier supplier) { + while (true) { + T result = value.get(); + if (result != null) { + return result; + } + T computed = supplier.get(); + if (value.compareAndSet(null, computed)) { + return computed; + } + } + } +}