Copilot commented on code in PR #3024:
URL: https://github.com/apache/hugegraph/pull/3024#discussion_r3310217210


##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/AbstractRocksDBProvider.java:
##########
@@ -0,0 +1,176 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Abstract base class for RocksDB providers that provides common utility 
methods.
+ * This class focuses only on the core abstraction of RocksDB open/close 
operations
+ * without complex configuration management.
+ */
+public abstract class AbstractRocksDBProvider implements RocksDBProvider {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(AbstractRocksDBProvider.class);
+
+    @Override
+    public final RocksDB openRocksDB(Options options, String dataPath) throws 
RocksDBException {
+        LOG.debug("Opening RocksDB with provider: {} at path: {}", 
getProviderName(), dataPath);
+
+        // Initialize provider if needed
+        initialize();
+
+        try {
+            // Delegate to provider-specific implementation
+            RocksDB rocksDB = doOpenRocksDB(options, dataPath);
+
+            return rocksDB;
+        } catch (Exception e) {
+            LOG.error("Failed to open RocksDB with provider: {} at path: {}",
+                      getProviderName(), dataPath, e);
+            throw e;
+        }

Review Comment:
   `catch (Exception e) { ... throw e; }` won’t compile here because this 
method only declares `throws RocksDBException`, but `e` is a generic checked 
`Exception`. Catch `RocksDBException` (and possibly `RuntimeException`) 
explicitly, or wrap unexpected exceptions into a new 
`RocksDBException`/`RuntimeException` before rethrowing.



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/AbstractRocksDBProvider.java:
##########
@@ -0,0 +1,176 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Abstract base class for RocksDB providers that provides common utility 
methods.
+ * This class focuses only on the core abstraction of RocksDB open/close 
operations
+ * without complex configuration management.
+ */
+public abstract class AbstractRocksDBProvider implements RocksDBProvider {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(AbstractRocksDBProvider.class);
+
+    @Override
+    public final RocksDB openRocksDB(Options options, String dataPath) throws 
RocksDBException {
+        LOG.debug("Opening RocksDB with provider: {} at path: {}", 
getProviderName(), dataPath);
+
+        // Initialize provider if needed
+        initialize();
+
+        try {
+            // Delegate to provider-specific implementation
+            RocksDB rocksDB = doOpenRocksDB(options, dataPath);
+
+            return rocksDB;
+        } catch (Exception e) {
+            LOG.error("Failed to open RocksDB with provider: {} at path: {}",
+                      getProviderName(), dataPath, e);
+            throw e;
+        }
+    }
+
+    @Override
+    public final RocksDB openRocksDB(DBOptions dbOptions, String dataPath,
+                                     List<ColumnFamilyDescriptor> 
cfDescriptors,
+                                     List<ColumnFamilyHandle> cfHandles) 
throws RocksDBException {
+        // Initialize provider if needed
+        initialize();
+
+        try {
+            // Delegate to provider-specific implementation
+            RocksDB rocksDB = doOpenRocksDB(dbOptions, dataPath, 
cfDescriptors, cfHandles);
+
+            return rocksDB;
+        } catch (Exception e) {
+            LOG.error("Failed to open RocksDB with column families using 
provider: {} at path: {}",
+                      getProviderName(), dataPath, e);
+            throw e;
+        }

Review Comment:
   Same issue as above: `catch (Exception e) { ... throw e; }` won’t compile in 
a method that only declares `throws RocksDBException`. Narrow the catch to 
`RocksDBException` or wrap other checked exceptions before rethrowing.



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/StandardRocksDBProvider.java:
##########
@@ -0,0 +1,146 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Standard RocksDB provider implementation that uses the standard RocksDB 
library.
+ * This provider handles the traditional RocksDB opening and configuration 
logic.
+ */
+public class StandardRocksDBProvider extends AbstractRocksDBProvider {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(StandardRocksDBProvider.class);
+
+    private static final String PROVIDER_NAME = "standard";
+    private static final int PROVIDER_PRIORITY = 100; // Lower priority than 
ToplingDB
+
+    @Override
+    public String getProviderName() {
+        return PROVIDER_NAME;
+    }
+
+    @Override
+    public int getPriority() {
+        return PROVIDER_PRIORITY;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        try {
+            // Check if standard RocksDB is available
+            RocksDB.loadLibrary();
+            return true;
+        } catch (Exception e) {
+            LOG.warn("Standard RocksDB is not available: {}", e.getMessage());
+            return false;
+        }
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(Options options, String dataPath) throws 
RocksDBException {
+        try {
+            return RocksDB.open(options, dataPath);
+        } catch (RocksDBException e) {
+            throw e;
+        }
+    }
+
+    @Override
+    public RocksDB openRocksDB(Options options, String dataPath, String 
optionPath,
+                               Boolean openHttp) throws RocksDBException {
+        return doOpenRocksDB(options, dataPath, optionPath, openHttp);
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(Options options, String dataPath, String 
optionPath,
+                                    Boolean openHttp) throws RocksDBException {
+        LOG.debug("Opening standard RocksDB with Options and extended 
parameters at path: {}",
+                  dataPath);
+
+        // Log warnings for unsupported parameters
+        if (optionPath != null) {
+            LOG.warn("Standard RocksDB does not support optionPath parameter, 
ignoring: {}",
+                     optionPath);
+        }
+        if (openHttp != null && openHttp) {
+            LOG.warn("Standard RocksDB does not support HTTP server, ignoring 
openHttp parameter");
+        }
+
+        // Use standard opening
+        return RocksDB.open(options, dataPath);
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(DBOptions dbOptions, String dataPath,
+                                    List<ColumnFamilyDescriptor> cfDescriptors,
+                                    List<ColumnFamilyHandle> cfHandles) throws 
RocksDBException {
+        try {
+            return RocksDB.open(dbOptions, dataPath, cfDescriptors, cfHandles);
+        } catch (RocksDBException e) {
+            throw e;
+        }
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(DBOptions dbOptions, String dataPath,
+                                    List<ColumnFamilyDescriptor> cfDescriptors,
+                                    List<ColumnFamilyHandle> cfHandles,
+                                    String optionPath, Boolean openHttp) 
throws RocksDBException {
+        // Standard RocksDB doesn't support optionPath and openHttp parameters
+        // Log a warning if these parameters are provided
+        if (optionPath != null && !optionPath.isEmpty()) {
+            LOG.warn("Standard RocksDB provider does not support optionPath 
parameter: {}",
+                     optionPath);
+        }
+        if (openHttp != null && openHttp) {
+            LOG.warn("Standard RocksDB provider does not support openHttp 
parameter");
+        }
+
+        // Fallback to standard column family opening
+        return doOpenRocksDB(dbOptions, dataPath, cfDescriptors, cfHandles);
+    }
+
+    @Override
+    public void initialize() {
+        try {
+            // Load RocksDB native library
+            RocksDB.loadLibrary();
+            LOG.debug("Standard RocksDB library loaded successfully");
+        } catch (Exception e) {
+            LOG.error("Failed to load standard RocksDB library", e);
+            throw new RuntimeException("Failed to initialize standard RocksDB 
provider", e);
+        }

Review Comment:
   Same `UnsatisfiedLinkError` risk as in `isAvailable()`: 
`RocksDB.loadLibrary()` can throw `Error` types. Catching only `Exception` may 
terminate initialization instead of failing provider selection gracefully.



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/AbstractRocksDBProvider.java:
##########
@@ -0,0 +1,176 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Abstract base class for RocksDB providers that provides common utility 
methods.
+ * This class focuses only on the core abstraction of RocksDB open/close 
operations
+ * without complex configuration management.
+ */
+public abstract class AbstractRocksDBProvider implements RocksDBProvider {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(AbstractRocksDBProvider.class);
+
+    @Override
+    public final RocksDB openRocksDB(Options options, String dataPath) throws 
RocksDBException {
+        LOG.debug("Opening RocksDB with provider: {} at path: {}", 
getProviderName(), dataPath);
+
+        // Initialize provider if needed
+        initialize();
+
+        try {
+            // Delegate to provider-specific implementation
+            RocksDB rocksDB = doOpenRocksDB(options, dataPath);
+
+            return rocksDB;
+        } catch (Exception e) {
+            LOG.error("Failed to open RocksDB with provider: {} at path: {}",
+                      getProviderName(), dataPath, e);
+            throw e;
+        }
+    }
+
+    @Override
+    public final RocksDB openRocksDB(DBOptions dbOptions, String dataPath,
+                                     List<ColumnFamilyDescriptor> 
cfDescriptors,
+                                     List<ColumnFamilyHandle> cfHandles) 
throws RocksDBException {
+        // Initialize provider if needed
+        initialize();
+
+        try {
+            // Delegate to provider-specific implementation
+            RocksDB rocksDB = doOpenRocksDB(dbOptions, dataPath, 
cfDescriptors, cfHandles);
+
+            return rocksDB;
+        } catch (Exception e) {
+            LOG.error("Failed to open RocksDB with column families using 
provider: {} at path: {}",
+                      getProviderName(), dataPath, e);
+            throw e;
+        }
+    }
+
+    @Override
+    public final RocksDB openRocksDB(DBOptions dbOptions, String dataPath,
+                                     List<ColumnFamilyDescriptor> 
cfDescriptors,
+                                     List<ColumnFamilyHandle> cfHandles,
+                                     String optionPath, Boolean openHttp) 
throws RocksDBException {
+
+        LOG.debug("Opening RocksDB with extended parameters using provider: {} 
at path: {}",
+                  getProviderName(), dataPath);
+        // Initialize provider if needed
+        initialize();
+
+        try {
+            // Delegate to provider-specific implementation
+            RocksDB rocksDB =
+                    doOpenRocksDB(dbOptions, dataPath, cfDescriptors, 
cfHandles, optionPath,
+                                  openHttp);
+            return rocksDB;
+        } catch (Exception e) {
+            throw e;
+        }

Review Comment:
   `catch (Exception e) { throw e; }` won’t compile here for the same reason: 
the method signature only allows `RocksDBException`. Either catch/rethrow 
`RocksDBException` explicitly or wrap unexpected checked exceptions.



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/StandardRocksDBProvider.java:
##########
@@ -0,0 +1,146 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Standard RocksDB provider implementation that uses the standard RocksDB 
library.
+ * This provider handles the traditional RocksDB opening and configuration 
logic.
+ */
+public class StandardRocksDBProvider extends AbstractRocksDBProvider {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(StandardRocksDBProvider.class);
+
+    private static final String PROVIDER_NAME = "standard";
+    private static final int PROVIDER_PRIORITY = 100; // Lower priority than 
ToplingDB
+
+    @Override
+    public String getProviderName() {
+        return PROVIDER_NAME;
+    }
+
+    @Override
+    public int getPriority() {
+        return PROVIDER_PRIORITY;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        try {
+            // Check if standard RocksDB is available
+            RocksDB.loadLibrary();
+            return true;
+        } catch (Exception e) {
+            LOG.warn("Standard RocksDB is not available: {}", e.getMessage());

Review Comment:
   `RocksDB.loadLibrary()` can fail with `UnsatisfiedLinkError` (an `Error`, 
not an `Exception`). Catching only `Exception` here can crash provider 
discovery on hosts without native libs. Consider catching `Throwable` (or at 
least `LinkageError`/`UnsatisfiedLinkError`) and returning `false` with a log 
message.
   



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/RocksDBProviderLoader.java:
##########
@@ -0,0 +1,290 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.ColumnFamilyDescriptor;
+import org.rocksdb.ColumnFamilyHandle;
+import org.rocksdb.DBOptions;
+import org.rocksdb.Options;
+import org.rocksdb.RocksDB;
+import org.rocksdb.RocksDBException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * RocksDB Provider SPI Loader that manages the loading and selection
+ * of RocksDB providers using Java's ServiceLoader mechanism.
+ */
+public class RocksDBProviderLoader {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(RocksDBProviderLoader.class);
+
+    private static final RocksDBProviderLoader INSTANCE = new 
RocksDBProviderLoader();
+
+    private final Map<String, RocksDBProvider> providerCache = new 
ConcurrentHashMap<>();
+    private volatile boolean loaded = false;
+    private volatile RocksDBProvider bestProvider = null;
+
+    private RocksDBProviderLoader() {
+        // Private constructor for singleton
+    }
+
+    public static RocksDBProviderLoader getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Load all available RocksDB providers using SPI
+     */
+    public synchronized void loadProviders() {
+        if (loaded) {
+            return;
+        }
+
+        LOG.info("Loading RocksDB providers via SPI...");
+
+        ServiceLoader<RocksDBProvider> serviceLoader = 
ServiceLoader.load(RocksDBProvider.class);
+
+        for (RocksDBProvider provider : serviceLoader) {
+            try {
+                if (provider.isAvailable()) {
+                    providerCache.put(provider.getProviderName(), provider);
+                    LOG.info("Loaded RocksDB provider: {} (priority: {})",
+                             provider.getProviderName(), 
provider.getPriority());
+                } else {
+                    LOG.warn("RocksDB provider {} is not available in current 
environment",
+                             provider.getProviderName());
+                }
+            } catch (Exception e) {
+                LOG.error("Failed to load RocksDB provider: {}", 
provider.getClass().getName(), e);
+            }
+        }
+
+        if (providerCache.isEmpty()) {
+            LOG.warn(
+                    "No RocksDB providers found! Make sure providers are 
properly registered in " +
+                    "META-INF/services");
+        } else {
+            LOG.info("Successfully loaded {} RocksDB provider(s): {}",
+                     providerCache.size(), providerCache.keySet());
+        }
+
+        loaded = true;
+    }
+
+    /**
+     * Get a specific provider by name
+     *
+     * @param providerName provider name
+     * @return RocksDB provider or null if not found
+     */
+    public RocksDBProvider getProvider(String providerName) {
+        if (!loaded) {
+            loadProviders();
+        }
+
+        return providerCache.get(providerName);
+    }
+
+    /**
+     * Get the best available provider based on priority
+     *
+     * @return best available RocksDB provider
+     */
+    public RocksDBProvider getBestProvider() {
+        if (!loaded) {
+            loadProviders();
+        }
+
+        RocksDBProvider cached = this.bestProvider;
+        if (cached != null) {
+            return cached;
+        }
+
+        if (providerCache.isEmpty()) {
+            throw new RuntimeException("No RocksDB providers available");
+        }
+
+        synchronized (this) {
+            if (this.bestProvider != null) {
+                return this.bestProvider;
+            }
+
+            // Find provider with highest priority
+            RocksDBProvider selected = null;
+            int highestPriority = Integer.MIN_VALUE;
+
+            for (RocksDBProvider provider : providerCache.values()) {
+                if (provider.isAvailable() && provider.getPriority() > 
highestPriority) {
+                    selected = provider;
+                    highestPriority = provider.getPriority();
+                }
+            }

Review Comment:
   `getBestProvider()` calls `provider.isAvailable()` without guarding against 
`Error`s. If native loading fails with `UnsatisfiedLinkError`, this can crash 
DB open/close. Consider wrapping the `isAvailable()` call in try/catch 
(including `Throwable`) and treating failures as “not available”.



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/RocksDBProviderLoader.java:
##########
@@ -0,0 +1,290 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.ColumnFamilyDescriptor;
+import org.rocksdb.ColumnFamilyHandle;
+import org.rocksdb.DBOptions;
+import org.rocksdb.Options;
+import org.rocksdb.RocksDB;
+import org.rocksdb.RocksDBException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * RocksDB Provider SPI Loader that manages the loading and selection
+ * of RocksDB providers using Java's ServiceLoader mechanism.
+ */
+public class RocksDBProviderLoader {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(RocksDBProviderLoader.class);
+
+    private static final RocksDBProviderLoader INSTANCE = new 
RocksDBProviderLoader();
+
+    private final Map<String, RocksDBProvider> providerCache = new 
ConcurrentHashMap<>();
+    private volatile boolean loaded = false;
+    private volatile RocksDBProvider bestProvider = null;
+
+    private RocksDBProviderLoader() {
+        // Private constructor for singleton
+    }
+
+    public static RocksDBProviderLoader getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Load all available RocksDB providers using SPI
+     */
+    public synchronized void loadProviders() {
+        if (loaded) {
+            return;
+        }
+
+        LOG.info("Loading RocksDB providers via SPI...");
+
+        ServiceLoader<RocksDBProvider> serviceLoader = 
ServiceLoader.load(RocksDBProvider.class);
+
+        for (RocksDBProvider provider : serviceLoader) {
+            try {
+                if (provider.isAvailable()) {
+                    providerCache.put(provider.getProviderName(), provider);
+                    LOG.info("Loaded RocksDB provider: {} (priority: {})",
+                             provider.getProviderName(), 
provider.getPriority());
+                } else {
+                    LOG.warn("RocksDB provider {} is not available in current 
environment",
+                             provider.getProviderName());
+                }
+            } catch (Exception e) {

Review Comment:
   `provider.isAvailable()` can throw `UnsatisfiedLinkError`/other `Error`s 
(see `StandardRocksDBProvider.isAvailable()`), but this loop only catches 
`Exception`. An `Error` would abort provider loading and potentially crash the 
process. Consider catching `Throwable` around provider 
instantiation/availability checks so a single broken provider can be skipped 
safely.
   



##########
hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/config/PDConfig.java:
##########
@@ -58,6 +58,11 @@ public class PDConfig {
     @Value("${grpc.host}")
     private String host;
 
+    @Value("${rocksdb.option-path: ''}")

Review Comment:
   With `@Value("${rocksdb.option-path: ''}")`, the default becomes the literal 
string `''` (including quotes/spaces) rather than an empty string. That makes 
`optionPath` non-empty by default and will trigger Topling/RocksDB option-path 
validation and warning logs even when users didn’t configure it. Consider using 
an actual empty default like `${rocksdb.option-path:}` (or 
`${rocksdb.option-path:}` + `.trim()` when consuming).
   



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/ToplingRocksDBProvider.java:
##########
@@ -0,0 +1,614 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Locale;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import net.minidev.json.JSONObject;
+
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.BaseConstructor;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.LoaderOptions;
+
+/**
+ * ToplingRocksDBProvider provides ToplingDB-specific RocksDB functionality.
+ * This provider supports advanced ToplingDB features including:
+ * - YAML-based configuration via optionPath
+ * - HTTP server for monitoring and management
+ * - SidePluginRepo integration for enhanced performance
+ */
+public class ToplingRocksDBProvider extends AbstractRocksDBProvider {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ToplingRocksDBProvider.class);
+
+    private static final String PROVIDER_NAME = "topling";
+    private static final int PROVIDER_PRIORITY = 200; // Higher priority than 
standard
+    private static final String SIDE_PLUGIN_REPO_CLASS = 
"org.rocksdb.SidePluginRepo";
+
+    // Validation constants migrated from RocksDBOptions
+    private static final Pattern SAFE_PATH_PATTERN =
+            Pattern.compile("^[a-zA-Z0-9/_.-]+\\.ya?ml$");
+    private static final String ALLOWED_CONFIG_DIR = "./conf/";
+    private static final long MAX_CONFIG_FILE_SIZE = 1024 * 1024 * 10; // 10 MB
+
+    // Store repo objects for proper cleanup
+    private final Map<RocksDB, Object> rocksDBToRepoMap = new 
ConcurrentHashMap<>();
+
+    @Override
+    public String getProviderName() {
+        return PROVIDER_NAME;
+    }
+
+    @Override
+    public int getPriority() {
+        return PROVIDER_PRIORITY;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        try {
+            // Check if SidePluginRepo class is available
+            Class.forName(SIDE_PLUGIN_REPO_CLASS);
+            LOG.info("ToplingDB SidePluginRepo found, ToplingRocksDBProvider 
is available");
+            return true;
+        } catch (ClassNotFoundException e) {
+            LOG.debug(
+                    "ToplingDB SidePluginRepo not found, 
ToplingRocksDBProvider is not available:" +
+                    " {}",
+                    e.getMessage());
+            return false;
+        }
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(Options options, String dataPath) throws 
RocksDBException {
+        LOG.info("Opening RocksDB with Options at path: {}", dataPath);
+
+        // For simple Options-based opening without optionPath, use standard 
RocksDB.open
+        return RocksDB.open(options, dataPath);
+    }
+
+    @Override
+    public RocksDB openRocksDB(Options options, String dataPath, String 
optionPath,
+                               Boolean openHttp) throws RocksDBException {
+        initialize();
+        return doOpenRocksDB(options, dataPath, optionPath, openHttp);
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(Options options, String dataPath, String 
optionPath,
+                                    Boolean openHttp) throws RocksDBException {
+        // Check if we should use ToplingDB features
+        boolean useTopling = validateConfiguration(optionPath);
+
+        if (useTopling) {
+            return openWithToplingFeatures(options, dataPath, optionPath, 
openHttp);
+        } else {
+            logStandardFallback(optionPath);
+            return RocksDB.open(options, dataPath);
+        }
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(DBOptions dbOptions, String dataPath,
+                                    List<ColumnFamilyDescriptor> cfDescriptors,
+                                    List<ColumnFamilyHandle> cfHandles) throws 
RocksDBException {
+        LOG.info("Opening RocksDB with DBOptions and column families at path: 
{}", dataPath);
+
+        // For column family opening without ToplingDB features, use standard 
RocksDB.open
+        return RocksDB.open(dbOptions, dataPath, cfDescriptors, cfHandles);
+    }
+
+    @Override
+    protected RocksDB doOpenRocksDB(DBOptions dbOptions, String dataPath,
+                                    List<ColumnFamilyDescriptor> cfDescriptors,
+                                    List<ColumnFamilyHandle> cfHandles,
+                                    String optionPath, Boolean openHttp) 
throws RocksDBException {
+        // Check if we should use ToplingDB features
+        boolean useTopling = validateConfiguration(optionPath);
+
+        if (useTopling) {
+            // For ToplingDB with column families, we need to use the standard 
RocksDB.open method
+            // but with ToplingDB-specific initialization through 
SidePluginRepo
+            return openWithToplingFeaturesAndCF(dbOptions, dataPath, 
cfDescriptors, cfHandles,
+                                                optionPath, openHttp);
+        } else {
+            logStandardFallback(optionPath);
+            return RocksDB.open(dbOptions, dataPath, cfDescriptors, cfHandles);
+        }
+    }
+
+    /**
+     * Opens RocksDB using ToplingDB features with SidePluginRepo
+     */
+    private RocksDB openWithToplingFeatures(Options options, String dataPath,
+                                            String optionPath, Boolean 
openHttp)
+            throws RocksDBException {
+        Object repo = null;
+        RocksDB opened = null;
+        boolean registered = false;
+        try {
+            // Initialize ToplingDB repo with common operations
+            repo = initializeToplingRepo(options, dataPath, optionPath);
+
+            // Open database with default column families
+            Class<?> sidePluginRepoClass = repo.getClass();
+            Method openDBMethod = sidePluginRepoClass.getMethod("openDB", 
String.class);
+            Object result = openDBMethod.invoke(repo, 
converseOptionsToJsonString(dataPath, null));
+
+            // Validate and store result before starting HTTP server
+            opened = validateAndStoreResult(result, repo, dataPath, 0);
+            registered = true;
+
+            // Start HTTP server if needed
+            startHttpServerIfNeeded(repo, dataPath, openHttp, optionPath);
+
+            return opened;
+
+        } catch (InvocationTargetException e) {
+            cleanupFailedOpen(opened, repo, registered, null);
+            Throwable cause = e.getCause();
+            if (cause instanceof RocksDBException) {
+                throw (RocksDBException) cause;
+            }
+            throw new RocksDBException(
+                    "Failed to open DB with SidePluginRepo: " + 
cause.getMessage());
+        } catch (Exception e) {
+            cleanupFailedOpen(opened, repo, registered, null);
+            throw new RocksDBException("Failed to open ToplingDB: " + 
e.getMessage());
+        }
+    }
+
+    /**
+     * Open RocksDB with ToplingDB features and column families support
+     */
+    private RocksDB openWithToplingFeaturesAndCF(DBOptions dbOptions, String 
dataPath,
+                                                 List<ColumnFamilyDescriptor> 
cfDescriptors,
+                                                 List<ColumnFamilyHandle> 
cfHandles,
+                                                 String optionPath, Boolean 
openHttp)
+            throws RocksDBException {
+        Object repo = null;
+        RocksDB opened = null;
+        boolean registered = false;
+        try {
+            // Initialize ToplingDB repo with common operations
+            repo = initializeToplingRepo(dbOptions, dataPath, optionPath);
+
+            // Prepare column family names for JSON
+            List<String> cfNames = new java.util.ArrayList<>();
+            for (ColumnFamilyDescriptor cfDescriptor : cfDescriptors) {
+                cfNames.add(new String(cfDescriptor.getName()));

Review Comment:
   Column-family names are decoded using the platform default charset (`new 
String(byte[])`). CF names in RocksDB are byte sequences and in this codebase 
are typically UTF-8 encoded; using the platform default can lead to incorrect 
names on non-UTF8 default locales. Prefer `new String(bytes, 
StandardCharsets.UTF_8)`.
   



##########
hugegraph-rocksdb-provider/pom.xml:
##########
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>hugegraph-rocksdb-provider</artifactId>
+    <version>${revision}</version>
+
+    <name>${project.artifactId}</name>
+    <description>
+        HugeGraph RocksDB Provider - A common adapter module for RocksDB and 
ToplingDB integration
+        using SPI (Service Provider Interface) and Strategy Pattern for loose 
coupling and plugin-based architecture.
+    </description>
+
+    <parent>
+        <artifactId>hugegraph</artifactId>
+        <groupId>org.apache.hugegraph</groupId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <dependencies>
+        <!-- RocksDB dependency -->
+        <dependency>
+            <groupId>org.rocksdb</groupId>
+            <artifactId>rocksdbjni</artifactId>
+            <version>${rocksdbjni.version}</version>
+        </dependency>
+
+        <!-- HugeGraph Commons for configuration and utilities -->
+        <dependency>
+            <groupId>org.apache.hugegraph</groupId>
+            <artifactId>hugegraph-common</artifactId>
+            <version>${hugegraph-commons.version}</version>
+        </dependency>
+
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.5</version>

Review Comment:
   This module pins `slf4j-api` to `1.7.5`, which is significantly older than 
versions already present in the repo and may downgrade the resolved SLF4J API 
for downstream modules. The codebase explicitly excludes older `slf4j-api` 
versions elsewhere to avoid this (e.g. 
`hugegraph-server/hugegraph-hbase/pom.xml` excludes it as “redundant older 
version”). Consider removing the explicit version (let Maven resolve 
consistently) or aligning it with the project’s chosen SLF4J version.
   



##########
hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/RocksDBProviderLoader.java:
##########
@@ -0,0 +1,290 @@
+/*
+ * 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.hugegraph.rocksdb.provider;
+
+import org.rocksdb.ColumnFamilyDescriptor;
+import org.rocksdb.ColumnFamilyHandle;
+import org.rocksdb.DBOptions;
+import org.rocksdb.Options;
+import org.rocksdb.RocksDB;
+import org.rocksdb.RocksDBException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * RocksDB Provider SPI Loader that manages the loading and selection
+ * of RocksDB providers using Java's ServiceLoader mechanism.
+ */
+public class RocksDBProviderLoader {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(RocksDBProviderLoader.class);
+
+    private static final RocksDBProviderLoader INSTANCE = new 
RocksDBProviderLoader();
+
+    private final Map<String, RocksDBProvider> providerCache = new 
ConcurrentHashMap<>();
+    private volatile boolean loaded = false;
+    private volatile RocksDBProvider bestProvider = null;
+
+    private RocksDBProviderLoader() {
+        // Private constructor for singleton
+    }
+
+    public static RocksDBProviderLoader getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Load all available RocksDB providers using SPI
+     */
+    public synchronized void loadProviders() {
+        if (loaded) {
+            return;
+        }
+
+        LOG.info("Loading RocksDB providers via SPI...");
+
+        ServiceLoader<RocksDBProvider> serviceLoader = 
ServiceLoader.load(RocksDBProvider.class);
+
+        for (RocksDBProvider provider : serviceLoader) {
+            try {
+                if (provider.isAvailable()) {
+                    providerCache.put(provider.getProviderName(), provider);
+                    LOG.info("Loaded RocksDB provider: {} (priority: {})",
+                             provider.getProviderName(), 
provider.getPriority());
+                } else {
+                    LOG.warn("RocksDB provider {} is not available in current 
environment",
+                             provider.getProviderName());
+                }
+            } catch (Exception e) {
+                LOG.error("Failed to load RocksDB provider: {}", 
provider.getClass().getName(), e);
+            }
+        }
+
+        if (providerCache.isEmpty()) {
+            LOG.warn(
+                    "No RocksDB providers found! Make sure providers are 
properly registered in " +
+                    "META-INF/services");
+        } else {
+            LOG.info("Successfully loaded {} RocksDB provider(s): {}",
+                     providerCache.size(), providerCache.keySet());
+        }
+
+        loaded = true;

Review Comment:
   There are no unit tests in this new module, but it contains non-trivial 
provider selection / fallback logic (SPI discovery, priority selection, 
open/close delegation). Adding focused tests (at least for provider selection 
ordering and fallback when a provider is unavailable) would help prevent 
regressions, especially since failures can be environment-specific.



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