xiangfu0 commented on code in PR #19926:
URL: https://github.com/apache/pinot/pull/19926#discussion_r4367673257


##########
pinot-common/src/main/java/org/apache/pinot/common/config/provider/BaseTableCache.java:
##########
@@ -0,0 +1,345 @@
+/**
+ * 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.pinot.common.config.provider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.apache.pinot.common.request.Expression;
+import org.apache.pinot.spi.config.provider.LogicalTableConfigChangeListener;
+import org.apache.pinot.spi.config.provider.SchemaChangeListener;
+import org.apache.pinot.spi.config.provider.TableConfigChangeListener;
+import org.apache.pinot.spi.config.table.TableConfig;
+import org.apache.pinot.spi.data.LogicalTableConfig;
+import org.apache.pinot.spi.data.Schema;
+import org.apache.pinot.spi.utils.builder.TableNameBuilder;
+
+
+/// Shared table, schema and logical-table cache for coordination adapters.
+/// Query reads use concurrent maps; each metadata family is updated 
independently, not as a cluster-wide snapshot.
+/// Adapters must hold the corresponding change lock through hydration, 
mutation and listener notification, and must
+/// supply ordered, decoded values. Listener registration uses the same lock 
so its initial callback cannot follow a
+/// newer update. Subscriptions, decoding and backend-specific versions remain 
the adapter's responsibility.
+public abstract class BaseTableCache implements TableCache {
+  private static final String OFFLINE_TABLE_SUFFIX = "_OFFLINE";
+  private static final String REALTIME_TABLE_SUFFIX = "_REALTIME";
+  private static final String LOWER_CASE_OFFLINE_TABLE_SUFFIX = 
OFFLINE_TABLE_SUFFIX.toLowerCase();
+  private static final String LOWER_CASE_REALTIME_TABLE_SUFFIX = 
REALTIME_TABLE_SUFFIX.toLowerCase();
+
+  protected final Object _tableConfigChangeLock = new Object();
+  protected final Object _schemaChangeLock = new Object();
+  protected final Object _logicalTableConfigChangeLock = new Object();
+
+  // Listener sets are only accessed while holding the corresponding change 
lock.
+  private final Set<TableConfigChangeListener> _tableConfigChangeListeners = 
new HashSet<>();
+  private final Set<SchemaChangeListener> _schemaChangeListeners = new 
HashSet<>();
+  private final Set<LogicalTableConfigChangeListener> 
_logicalTableConfigChangeListeners = new HashSet<>();
+  private final boolean _ignoreCase;
+  private final Map<String, TableConfigInfo> _tableConfigInfoMap = new 
ConcurrentHashMap<>();
+  private final Map<String, String> _tableNameMap = new ConcurrentHashMap<>();
+  private final Map<String, SchemaInfo> _schemaInfoMap = new 
ConcurrentHashMap<>();
+  private final Map<String, LogicalTableConfigInfo> _logicalTableConfigInfoMap 
= new ConcurrentHashMap<>();
+  private final Map<String, String> _logicalTableNameMap = new 
ConcurrentHashMap<>();
+
+  protected BaseTableCache(boolean ignoreCase) {
+    _ignoreCase = ignoreCase;
+  }
+
+  /// Returns `true` if the TableCache is case-insensitive, `false` otherwise.
+  @Override
+  public boolean isIgnoreCase() {
+    return _ignoreCase;
+  }
+
+  /// Returns the actual table name for the given table name (with or without 
type suffix), or `null` if the table
+  /// does not exist.
+  @Nullable
+  @Override
+  public String getActualTableName(String tableName) {
+    if (_ignoreCase) {
+      return _tableNameMap.get(tableName.toLowerCase());
+    } else {
+      return _tableNameMap.get(tableName);
+    }
+  }
+
+  /// Returns the actual logical table name for the given table name, or 
`null` if table does not exist.
+  /// @param logicalTableName Logical table name
+  /// @return Actual logical table name
+  @Nullable
+  @Override
+  public String getActualLogicalTableName(String logicalTableName) {
+    return _ignoreCase
+        ? _logicalTableNameMap.get(logicalTableName.toLowerCase())
+        : _logicalTableNameMap.get(logicalTableName);
+  }
+
+  /// Returns a map from table name to actual table name. For case-insensitive 
case, the keys of the map are in lower
+  /// case.
+  @Override
+  public Map<String, String> getTableNameMap() {
+    return _tableNameMap;
+  }
+
+  /// Returns a map from logical table name to actual logical table name. For 
case-insensitive case, the keys of the map
+  /// are in lower case.
+  /// @return Map from logical table name to actual logical table name
+  @Override
+  public Map<String, String> getLogicalTableNameMap() {
+    return _logicalTableNameMap;
+  }
+
+  /// Get all dimension table names.
+  /// @return List of dimension table names
+  @Override
+  public List<String> getAllDimensionTables() {
+    List<String> dimensionTables = new ArrayList<>();
+    for (TableConfigInfo tableConfigInfo : _tableConfigInfoMap.values()) {
+      if (tableConfigInfo._tableConfig.isDimTable()) {
+        dimensionTables.add(tableConfigInfo._tableConfig.getTableName());

Review Comment:
   Nice that the thread-safety contract is spelled out. One thing worth a line 
here for future backend authors: the read maps are plain ConcurrentHashMap and 
reads don't take the change lock, so a reader can observe a table config while 
its name-map entry is mid-update (same as the old ZkTableCache, so not a 
regression). Noting that reads give per-key, not snapshot, consistency would 
prevent a future adapter from assuming otherwise.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to