xushiyan commented on code in PR #5064:
URL: https://github.com/apache/hudi/pull/5064#discussion_r1035081191


##########
.gitignore:
##########
@@ -1,6 +1,7 @@
 # Directories #
 /build/
 target/
+hudi-metaserver/src/main/thrift/gen-java/

Review Comment:
   can we make generated source under `target/generated-sources/src`? where the 
avro models are also placed at



##########
hudi-metaserver/src/main/java/org/apache/hudi/metaserver/HoodieMetaServer.java:
##########
@@ -0,0 +1,123 @@
+/*
+ * 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.hudi.metaserver;
+
+import org.apache.hudi.exception.HoodieIOException;
+import org.apache.hudi.metaserver.service.HoodieMetaServerService;
+import org.apache.hudi.metaserver.service.HoodieMetaServerProxyHandler;
+import org.apache.hudi.metaserver.service.PartitionService;
+import org.apache.hudi.metaserver.service.TableService;
+import org.apache.hudi.metaserver.service.TimelineService;
+import org.apache.hudi.metaserver.store.RelationDBBasedStore;
+import org.apache.hudi.metaserver.store.MetadataStore;
+import org.apache.hudi.metaserver.thrift.MetaStoreException;
+import org.apache.hudi.metaserver.thrift.ThriftHoodieMetaServer;
+import org.apache.hudi.metaserver.util.TServerSocketWrapper;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TThreadPoolServer;
+import org.apache.thrift.transport.TServerTransport;
+
+import java.lang.reflect.Proxy;
+
+/**
+ * Main class of hoodie meta server.
+ */
+public class HoodieMetaServer {

Review Comment:
   let's annotate as experimental in javadoc



##########
hudi-metaserver/src/main/java/org/apache/hudi/metaserver/client/HoodieMetaServerClient.java:
##########
@@ -0,0 +1,56 @@
+/*
+ * 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.hudi.metaserver.client;
+
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hudi.common.table.timeline.HoodieInstant;
+import org.apache.hudi.common.util.Option;
+import org.apache.hudi.metaserver.thrift.Table;
+
+import java.util.List;
+
+/**
+ * Hoodie meta server client, is to get/put instants, instant meta, snapshot 
from/to hoodie meta server.
+ */
+public interface HoodieMetaServerClient {

Review Comment:
   let's annotate public interfaces with proper 
`org.apache.hudi.ApiMaturityLevel`



##########
hudi-metaserver/src/main/thrift/hudi-metaserver.thrift:
##########
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+ namespace java org.apache.hudi.metaserver.thrift
+
+ // table related
+ struct Table {
+   1: string tableName,
+   2: string dbName,
+   3: string owner,
+   4: i32 createTime,
+   5: string location,
+   6: string tableType,
+   7: list<FieldSchema> partitionKeys,
+   8: map<string, string> parameters
+ }
+
+ struct FieldSchema {
+   1: string name,
+   2: string type,
+   3: string comments
+ }
+
+// timeline related
+// align with actions defined in HoodieTimeline
+enum TAction {
+    COMMIT = 1,
+    DELTACOMMIT = 2,
+    CLEAN = 3,
+    ROLLBACK = 4,
+    SAVEPOINT = 5,
+    REPLACECOMMIT = 6,
+    COMPACTION = 7,
+    RESTORE = 8
+}
+
+// align with states defined in HoodieInstant
+enum TState {
+   REQUESTED = 1,
+   INFLIGHT = 2,
+   COMPLETED = 3,
+   INVALID = 4
+}
+
+struct THoodieInstant {
+   1: string timestamp,
+   2: TAction action,
+   3: TState state
+}
+
+struct HoodieInstantChangeResult {
+  1: bool success,
+  2: optional THoodieInstant instant,
+  4: optional string msg
+}
+
+exception MetaStoreException {

Review Comment:
   let's follow a naming convention: `Metastore` being 1 word, like 
`Metaserver`. Actually `MetaserverStorage` is more accurate to describe the 
underlying storage.



##########
hudi-metaserver/src/test/java/org/apache/hudi/metaserver/TestHoodieMetaServer.java:
##########
@@ -0,0 +1,28 @@
+/*
+ * 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.hudi.metaserver;
+
+import org.junit.jupiter.api.Test;
+
+public class TestHoodieMetaServer {
+  @Test
+  public void testEmbeddedServer() {
+    HoodieMetaServer.getMetadataStore();

Review Comment:
   this UT is too barely minimum. can we assert some conditions here?



##########
hudi-metaserver/src/main/thrift/hudi-metaserver.thrift:
##########
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+ namespace java org.apache.hudi.metaserver.thrift
+
+ // table related
+ struct Table {
+   1: string tableName,
+   2: string dbName,
+   3: string owner,
+   4: i32 createTime,
+   5: string location,
+   6: string tableType,
+   7: list<FieldSchema> partitionKeys,
+   8: map<string, string> parameters
+ }
+
+ struct FieldSchema {
+   1: string name,
+   2: string type,
+   3: string comments
+ }
+
+// timeline related
+// align with actions defined in HoodieTimeline
+enum TAction {
+    COMMIT = 1,
+    DELTACOMMIT = 2,
+    CLEAN = 3,
+    ROLLBACK = 4,
+    SAVEPOINT = 5,
+    REPLACECOMMIT = 6,
+    COMPACTION = 7,
+    RESTORE = 8
+}
+
+// align with states defined in HoodieInstant
+enum TState {
+   REQUESTED = 1,
+   INFLIGHT = 2,
+   COMPLETED = 3,
+   INVALID = 4
+}
+
+struct THoodieInstant {
+   1: string timestamp,
+   2: TAction action,
+   3: TState state
+}
+
+struct HoodieInstantChangeResult {
+  1: bool success,
+  2: optional THoodieInstant instant,
+  4: optional string msg
+}
+
+exception MetaStoreException {
+  1: string message
+}
+
+exception MetaException {

Review Comment:
   MetaException sounds weird: is it meant for Metaserver ?



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/config/HoodieWriteConfig.java:
##########
@@ -28,7 +28,7 @@
 import org.apache.hudi.common.config.HoodieCommonConfig;
 import org.apache.hudi.common.config.HoodieConfig;
 import org.apache.hudi.common.config.HoodieMetadataConfig;
-import org.apache.hudi.common.config.HoodieMetastoreConfig;
+import org.apache.hudi.common.config.HoodieMetaServerConfig;

Review Comment:
   let's align on name `metaserver` being 1 word so no camelCase



##########
hudi-metaserver/src/main/java/org/apache/hudi/common/table/view/HoodieMetaServerFileSystemView.java:
##########
@@ -0,0 +1,54 @@
+/*
+ * 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.hudi.common.table.view;
+
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.Path;
+import org.apache.hudi.common.config.HoodieMetaServerConfig;
+import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.table.timeline.HoodieTimeline;
+import org.apache.hudi.metaserver.client.HoodieMetaServerClient;
+import org.apache.hudi.metaserver.client.HoodieMetaServerClientProxy;
+
+import java.io.IOException;
+
+/**
+ * TableFileSystemView Implementations based on in-memory storage and
+ * is specifically for hoodie table whose metadata is stored in the hoodie 
meta server.
+ */
+public class HoodieMetaServerFileSystemView extends HoodieTableFileSystemView {
+  private String databaseName;
+  private String tableName;
+
+  private HoodieMetaServerClient metaServerClient;
+
+  public HoodieMetaServerFileSystemView(HoodieTableMetaClient metaClient,
+                                        HoodieTimeline visibleActiveTimeline, 
HoodieMetaServerConfig config) {
+    super(metaClient, visibleActiveTimeline);
+    this.metaServerClient = HoodieMetaServerClientProxy.getProxy(config);
+    this.databaseName = metaClient.getTableConfig().getDatabaseName();
+    this.tableName = metaClient.getTableConfig().getTableName();
+  }
+
+  protected FileStatus[] listPartition(Path partitionPath) throws IOException {
+    // TODO: support get snapshot from meta server

Review Comment:
   if not supported yet, let's remove it from this version. or throw 
unsupported exception



##########
hudi-metaserver/src/main/java/org/apache/hudi/metaserver/client/HoodieMetaServerClientImp.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * 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.hudi.metaserver.client;
+
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hudi.common.config.HoodieMetaServerConfig;
+import org.apache.hudi.common.table.timeline.HoodieInstant;
+import org.apache.hudi.common.util.Option;
+import org.apache.hudi.exception.HoodieException;
+import org.apache.hudi.metaserver.HoodieMetaServer;
+import org.apache.hudi.metaserver.thrift.Table;
+import org.apache.hudi.metaserver.thrift.ThriftHoodieMetaServer;
+import org.apache.hudi.metaserver.util.EntryConvertor;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * HoodieMetaServerClientImp based on thrift.
+ */
+public class HoodieMetaServerClientImp implements HoodieMetaServerClient, 
Serializable {
+
+  private static final Logger LOG =  
LogManager.getLogger(HoodieMetaServerClientImp.class);
+  private final HoodieMetaServerConfig config;
+  private final int retryLimit;
+  private final int retryDelaySeconds;
+  private boolean isConnected;
+  private boolean isLocal;
+  private ThriftHoodieMetaServer.Iface client;
+  private TTransport transport;
+
+  public HoodieMetaServerClientImp(HoodieMetaServerConfig config) {
+    this.config = config;
+    this.retryLimit = config.getConnectionRetryLimit();
+    this.retryDelaySeconds = config.getConnectionRetryDelay();
+    String uri = config.getMetaServerUris();
+    if (isLocalEmbeddedMetaServer(uri)) {
+      this.client = HoodieMetaServer.getEmbeddedMetaServer();
+      this.isConnected = true;
+      this.isLocal = true;
+    } else {
+      open();
+    }
+  }
+
+  private void open() {
+    String uri = config.getMetaServerUris();
+    TTransportException exception = null;
+    for (int i = 0; !isConnected && i < retryLimit; i++) {
+      try {
+        URI msUri = new URI(uri);

Review Comment:
   prefer `URI.create()`



##########
hudi-metaserver/src/main/java/org/apache/hudi/metaserver/service/TableService.java:
##########
@@ -0,0 +1,83 @@
+/*
+ * 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.hudi.metaserver.service;
+
+import org.apache.hudi.common.model.HoodieTableType;
+import org.apache.hudi.metaserver.store.MetadataStore;
+import org.apache.hudi.metaserver.thrift.AlreadyExistException;
+import org.apache.hudi.metaserver.thrift.MetaException;
+import org.apache.hudi.metaserver.thrift.MetaStoreException;
+import org.apache.hudi.metaserver.thrift.NoSuchObjectException;
+import org.apache.hudi.metaserver.thrift.Table;
+
+import java.io.Serializable;
+
+/**
+ * Handle all database / table related requests.
+ */
+public class TableService implements Serializable {
+  private MetadataStore store;
+
+  public TableService(MetadataStore metadataStore) {
+    this.store = metadataStore;
+  }
+
+  public void createDatabase(String db) throws AlreadyExistException, 
MetaStoreException, MetaException {
+    // todo: define the database entry in the thrift
+    if (databaseExists(db)) {
+      throw new AlreadyExistException("Database " + db + " already exists");
+    }
+    if (!store.createDatabase(db)) {
+      throw new MetaException("Fail to create the database: " + db);

Review Comment:
   any further info to retrieve when return false here?



##########
hudi-metaserver/src/main/resources/hikariPool.properties:
##########
@@ -0,0 +1,20 @@
+###
+# 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.
+###
+jdbcUrl=jdbc:h2:mem:bms;MODE=MYSQL

Review Comment:
   this is under `main/resources` ? thought this is for testing



##########
hudi-metaserver/src/main/java/org/apache/hudi/metaserver/util/EntryConvertor.java:
##########
@@ -0,0 +1,115 @@
+/*
+ * 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.hudi.metaserver.util;
+
+import org.apache.hudi.common.table.timeline.HoodieInstant;
+import org.apache.hudi.common.table.timeline.HoodieTimeline;
+import org.apache.hudi.metaserver.thrift.TAction;
+import org.apache.hudi.metaserver.thrift.THoodieInstant;
+import org.apache.hudi.metaserver.thrift.TState;
+
+import java.util.Locale;
+
+/**
+ * A convertor between hoodie entity and thrift entity.
+ */
+public class EntryConvertor {

Review Comment:
   did you mean `EntityConvertor` ?



##########
hudi-metaserver/src/main/java/org/apache/hudi/metaserver/store/RelationDBBasedStore.java:
##########
@@ -0,0 +1,244 @@
+/*
+ * 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.hudi.metaserver.store;
+
+import org.apache.hudi.metaserver.store.bean.InstantBean;
+import org.apache.hudi.metaserver.store.bean.TableBean;
+import org.apache.hudi.metaserver.store.jdbc.WrapperDao;
+import org.apache.hudi.metaserver.thrift.MetaStoreException;
+import org.apache.hudi.metaserver.thrift.NoSuchObjectException;
+import org.apache.hudi.metaserver.thrift.Table;
+import org.apache.hudi.metaserver.thrift.THoodieInstant;
+import org.apache.hudi.metaserver.thrift.TState;
+
+import java.io.Serializable;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Metadata store based on relation database.
+ */
+public class RelationDBBasedStore implements MetadataStore, Serializable {
+
+  private final WrapperDao tableDao = new WrapperDao.TableDao();
+  private final WrapperDao partitionDao = new WrapperDao.PartitionDao();
+  private final WrapperDao timelineDao = new WrapperDao.TimelineDao();
+  private final WrapperDao fileDao = new WrapperDao.FileDao();
+
+  @Override
+  public void initStore() throws MetaStoreException {
+    WrapperDao dao = new WrapperDao("DDLMapper");
+    dao.updateBySql("createDBs", null);
+    dao.updateBySql("createTables", null);
+    dao.updateBySql("createTableParams", null);
+    dao.updateBySql("createPartitions", null);
+    dao.updateBySql("createTableTimestamp", null);
+    dao.updateBySql("createInstant", null);
+    dao.updateBySql("createInstantMeta", null);
+    dao.updateBySql("createFiles", null);
+  }
+
+  @Override
+  public boolean createDatabase(String db) throws MetaStoreException {
+    Map<String, Object> params = new HashMap<>();
+    params.put("databaseName", db);
+    return tableDao.insertBySql("insertDB", params) == 1;
+  }
+
+  @Override
+  public Long getDatabaseId(String db) throws MetaStoreException {
+    List<Long> ids = tableDao.queryForListBySql("selectDBId", db);
+    assertIfNotSingle(ids, "db " + db);
+    return ids.isEmpty() ? null : ids.get(0);
+  }
+
+  @Override
+  public boolean createTable(Long dbId, Table table) throws MetaStoreException 
{
+    Map<String, Object> params = new HashMap<>();
+    params.put("dbId", dbId);
+    TableBean tableBean = new TableBean(table);
+    params.put("tableBean", tableBean);
+    return tableDao.insertBySql("insertTable", params) == 1;
+  }
+
+  @Override
+  public Table getTable(String db, String tb) throws MetaStoreException, 
NoSuchObjectException {
+    Map<String, Object> params = new HashMap<>();
+    params.put("databaseName", db);
+    params.put("tableName", tb);
+    List<TableBean> table = tableDao.queryForListBySql("selectTable", params);
+    assertIfNotSingle(table, "table " + db + "." + tb);
+    return table.isEmpty() ? null : table.get(0).toTable();
+  }
+
+  @Override
+  public Long getTableId(String db, String tb) throws MetaStoreException {
+    Map<String, Object> params = new HashMap<>();
+    params.put("databaseName", db);
+    params.put("tableName", tb);
+    List<Long> ids = tableDao.queryForListBySql("selectTableId", params);
+    assertIfNotSingle(ids, "table " + db + "." + tb);
+    return ids.isEmpty() ? null : ids.get(0);
+  }
+
+  @Override
+  public List<String> getAllPartitions(long tableId) throws MetaStoreException 
{
+    List<String> partitionNames = 
partitionDao.queryForListBySql("selectAllPartitions", tableId);
+    return partitionNames;
+  }
+
+  @Override
+  public String createNewTimestamp(long tableId) throws MetaStoreException {
+    // todo: support SSS
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+    String oldTimestamp;
+    String newTimestamp;
+    boolean success;
+    try {
+      do {
+        oldTimestamp = getLatestTimestamp(tableId);
+        newTimestamp = oldTimestamp == null
+            ? sdf.format(new Date())
+            : sdf.format(Math.max(new Date().getTime(), 
sdf.parse(oldTimestamp).getTime() + 1000));
+        Map<String, Object> params = new HashMap<>();
+        params.put("tableId", tableId);
+        params.put("oldTimestamp", oldTimestamp);
+        params.put("newTimestamp", newTimestamp);
+        if (oldTimestamp == null) {
+          success = timelineDao.insertBySql("insertTimestamp", params) == 1;
+        } else {
+          success = timelineDao.updateBySql("updateTimestamp", params) == 1;
+        }
+      } while (!success);
+    } catch (ParseException e) {
+      throw new MetaStoreException("Fail to parse the timestamp, " + 
e.getMessage());
+    }
+    return newTimestamp;
+  }
+
+  private String getLatestTimestamp(long tableId) throws MetaStoreException {
+    List<String> timestamps = 
timelineDao.queryForListBySql("selectTimestampByTableId", tableId);
+    assertIfNotSingle(timestamps, "timestamp");
+    return timestamps.isEmpty() ? null : timestamps.get(0);
+  }
+
+  @Override
+  public boolean createInstant(long tableId, THoodieInstant instant) throws 
MetaStoreException {
+    InstantBean instantBean = new InstantBean(tableId, instant);
+    Map<String, Object> params = new HashMap<>();
+    params.put("instant", instantBean);
+    // todo: support heartbeat
+    params.put("duration", 120);
+    params.put("startTs", (int) (System.currentTimeMillis() / 1000L));
+    return timelineDao.insertBySql("insertInstant", params) == 1;
+  }
+
+  @Override
+  public boolean updateInstant(long tableId, THoodieInstant fromInstant, 
THoodieInstant toInstant) throws MetaStoreException {
+    InstantBean oldInstant = new InstantBean(tableId, fromInstant);
+    InstantBean newInstant = new InstantBean(tableId, toInstant);
+    Map<String, Object> params = new HashMap<>();
+    params.put("oldInstant", oldInstant);
+    params.put("newInstant", newInstant);
+    return timelineDao.updateBySql("updateInstant", params) == 1;
+  }
+
+  @Override
+  public boolean deleteInstant(long tableId, THoodieInstant instant) throws 
MetaStoreException {
+    Map<String, Object> params = new HashMap<>();
+    params.put("tableId", tableId);
+    params.put("ts", instant.getTimestamp());
+    return timelineDao.deleteBySql("deleteInstant", params) == 1;
+  }
+
+  @Override
+  public List<THoodieInstant> scanInstants(long tableId, List<TState> states, 
int limit) throws MetaStoreException {
+    if (states == null || states.isEmpty()) {
+      throw new MetaStoreException("State has to be specified when scan 
instants");
+    }
+    Map<String, Object> params = new HashMap<>();
+    params.put("tableId", tableId);
+    params.put("states", 
states.stream().mapToInt(TState::getValue).boxed().collect(Collectors.toList()));
+    params.put("limit", limit);
+    List<InstantBean> instantBeans = 
timelineDao.queryForListBySql("selectInstantsByStates", params);
+    return 
instantBeans.stream().map(InstantBean::toTHoodieInstant).collect(Collectors.toList());
+  }
+
+  @Override
+  public List<THoodieInstant> scanInstants(long tableId, TState state, int 
limit) throws MetaStoreException {
+    return scanInstants(tableId, Arrays.asList(state), limit);
+  }
+
+  @Override
+  public boolean instantExists(long tableId, THoodieInstant instant) throws 
MetaStoreException {
+    InstantBean instantBean = new InstantBean(tableId, instant);
+    List<Long> ids = timelineDao.queryForListBySql("selectInstantId", 
instantBean);
+    assertIfNotSingle(ids, instantBean.toString());
+    return !ids.isEmpty();
+  }
+
+  // todo: check correctness
+  @Override
+  public void saveInstantMeta(long tableId, THoodieInstant instant, byte[] 
metadata) throws MetaStoreException {
+    InstantBean instantBean = new InstantBean(tableId, instant);
+    Map<String, Object> params = new HashMap<>();
+    params.put("instant", instantBean);
+    params.put("metadata", metadata);
+    // todo: array bytes to longblob
+    timelineDao.insertBySql("insertInstantMeta", params);
+  }
+
+  @Override
+  public boolean deleteInstantMeta(long tableId, THoodieInstant instant) 
throws MetaStoreException {
+    InstantBean instantBean = new InstantBean(tableId, instant);
+    return timelineDao.deleteBySql("deleteInstantMeta", instantBean) == 1;
+  }
+
+  @Override
+  public boolean deleteInstantAllMeta(long tableId, String timestamp) throws 
MetaStoreException {
+    Map<String, Object> params = new HashMap<>();
+    params.put("tableId", tableId);
+    params.put("ts", timestamp);
+    return timelineDao.deleteBySql("deleteInstantAllMeta", params) >= 1;
+  }
+
+  @Override
+  public byte[] getInstantMeta(long tableId, THoodieInstant instant) throws 
MetaStoreException {
+    InstantBean instantBean = new InstantBean(tableId, instant);
+    Map<String, Object> result = 
timelineDao.queryForObjectBySql("selectInstantMeta", instantBean);
+    return result == null ? null : (byte[]) result.get("data");
+  }
+
+  @Override
+  public void close() {
+
+  }
+
+  public static void assertIfNotSingle(List<?> list, String errMsg) throws 
MetaStoreException {

Review Comment:
   make use of `ValidationUtils.checkState()` here as `assertXXX` is usually 
seen as a testing method



##########
pom.xml:
##########
@@ -2078,6 +2078,13 @@
         </property>
       </activation>
     </profile>
+
+    <profile>
+      <id>hudi-metaserver</id>
+      <modules>
+        <module>hudi-metaserver</module>

Review Comment:
   as discussed before, can we make it nested under `hudi-platform-service/`. 
Also can you clarify why we need a separate profile here?



-- 
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]

Reply via email to