Skip to content

Commit

Permalink
Merge branch 'apache:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
msgui authored Dec 7, 2023
2 parents c7d7c93 + 47aa8be commit 644e15e
Show file tree
Hide file tree
Showing 18 changed files with 302 additions and 91 deletions.
2 changes: 2 additions & 0 deletions .github/configs/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
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.
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/check-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches:
- /^release-.*$/
pull_request:

permissions:
contents: read

Expand All @@ -17,7 +17,7 @@ jobs:
SCRIPT_DEPENDENCY: hugegraph-server/hugegraph-dist/scripts/dependency
steps:
- name: Checkout source
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
Expand All @@ -44,7 +44,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v3
# Refer: https://github.com/actions/dependency-review-action
Expand Down
43 changes: 20 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,48 +30,44 @@ jobs:
JAVA_VERSION: [ '8', '11' ]

steps:
- name: Install JDK ${{ matrix.JAVA_VERSION }}
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.JAVA_VERSION }}
distribution: 'zulu'

- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2

- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Compile
run: |
mvn clean compile -U -Dmaven.javadoc.skip=true -ntp
- name: Install JDK 8
# TODO: Remove this step after install-backend.sh updated
- name: Install Java8 for backend
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'zulu'
- name: Prepare env and service

- name: Prepare backend environment
run: |
$TRAVIS_DIR/install-backend.sh $BACKEND
$TRAVIS_DIR/install-backend.sh $BACKEND && jps -l
- name: Install JDK ${{ matrix.JAVA_VERSION }}
- name: Install Java ${{ matrix.JAVA_VERSION }}
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.JAVA_VERSION }}
distribution: 'zulu'

- name: use staged maven repo settings
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2

- name: Use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
cp -vf .github/configs/settings.xml $HOME/.m2/settings.xml && cat $HOME/.m2/settings.xml
- name: Compile
run: |
mvn clean compile -U -Dmaven.javadoc.skip=true -ntp
- name: Run unit test
run: |
Expand Down Expand Up @@ -99,4 +95,5 @@ jobs:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ${{ env.REPORT_DIR }}/*.xml
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ on:
push:
branches: [ master, release-* ]
pull_request:
# The branches below must be a subset of the branches above
# branches: [ master ] # enable in all PR
# The branches below must be a subset of the branches above
# branches: [ master ] # enable in all PRs
schedule:
- cron: '33 0 * * 5'

Expand All @@ -27,7 +27,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Java JDK
uses: actions/setup-java@v3
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/licence-checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
jobs:
check-license:
runs-on: ubuntu-latest
env:
USE_STAGE: 'true' # Whether to include the stage repository.
steps:
- uses: actions/checkout@v4

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* 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.api.gremlin;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.apache.hugegraph.util.ExecutorUtil;
import org.glassfish.jersey.apache.connector.ApacheClientProperties;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.glassfish.jersey.message.GZipEncoder;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.WebTarget;

/**
* This class is a simplified class of AbstractRestClient from hugegraph-common.
* For some reason, we replace the rest implementation from jersey to okhttp.
* But GremlinClient still uses jersey-client to forward request, so we copy the old
* AbstractRestClient from hugegraph-common and rename the name to AbstractJerseyRestClient.
* Because we don't need the full feature of AbstractRestClient, so we reduce some useless code.
*/
public abstract class AbstractJerseyRestClient {

/**
* Time unit: hour
*/
private static final long TTL = 24L;
/**
* Time unit: ms
*/
private static final long IDLE_TIME = 40L * 1000L;
private static final String PROPERTY_MAX_TOTAL = "maxTotal";
private static final String PROPERTY_MAX_PER_ROUTE = "maxPerRoute";
private static final String PROPERTY_IDLE_TIME = "idleTime";
private static final String CONNECTION_MANAGER = ApacheClientProperties.CONNECTION_MANAGER;

private final Client client;
private final WebTarget webTarget;
private final PoolingHttpClientConnectionManager pool;
private ScheduledExecutorService cleanExecutor;

public AbstractJerseyRestClient(String url, int timeout, int maxTotal, int maxPerRoute) {
this(url, new ConfigBuilder().configTimeout(timeout)
.configPool(maxTotal, maxPerRoute)
.build());
}

public AbstractJerseyRestClient(String url, ClientConfig config) {
this.pool = configConnectionManager(config);

this.client = JerseyClientBuilder.newClient(config);
this.client.register(GZipEncoder.class);
this.webTarget = this.client.target(url);

cleanThreadPoolExecutor(config);
}

private static PoolingHttpClientConnectionManager configConnectionManager(ClientConfig conf) {
/*
* Using httpclient with connection pooling, and configuring the
* jersey connector. But the jersey that has been released in the maven central
* repository seems to have a bug: https://github.com/jersey/jersey/pull/3752
*/
PoolingHttpClientConnectionManager pool =
new PoolingHttpClientConnectionManager(TTL, TimeUnit.HOURS);
Integer maxTotal = (Integer) conf.getProperty(PROPERTY_MAX_TOTAL);
Integer maxPerRoute = (Integer) conf.getProperty(PROPERTY_MAX_PER_ROUTE);

if (maxTotal != null) {
pool.setMaxTotal(maxTotal);
}
if (maxPerRoute != null) {
pool.setDefaultMaxPerRoute(maxPerRoute);
}
conf.property(CONNECTION_MANAGER, pool);
conf.connectorProvider(new ApacheConnectorProvider());
return pool;
}

private void cleanThreadPoolExecutor(ClientConfig config) {
this.cleanExecutor = ExecutorUtil.newScheduledThreadPool("conn-clean-worker-%d");
Number idleTimeProp = (Number) config.getProperty(PROPERTY_IDLE_TIME);
final long idleTime = idleTimeProp == null ? IDLE_TIME : idleTimeProp.longValue();
final long checkPeriod = idleTime / 2L;
this.cleanExecutor.scheduleWithFixedDelay(() -> {
PoolStats stats = this.pool.getTotalStats();
int using = stats.getLeased() + stats.getPending();
if (using > 0) {
// Do clean only when all connections are idle
return;
}
// Release connections when all clients are inactive
this.pool.closeIdleConnections(idleTime, TimeUnit.MILLISECONDS);
this.pool.closeExpiredConnections();
}, checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
}

protected WebTarget getWebTarget() {
return this.webTarget;
}

public void close() {
try {
if (this.pool != null) {
this.pool.close();
this.cleanExecutor.shutdownNow();
}
} finally {
this.client.close();
}
}

private static class ConfigBuilder {

private final ClientConfig config;

ConfigBuilder() {
this.config = new ClientConfig();
}

public ConfigBuilder configTimeout(int timeout) {
this.config.property(ClientProperties.CONNECT_TIMEOUT, timeout);
this.config.property(ClientProperties.READ_TIMEOUT, timeout);
return this;
}

public ConfigBuilder configPool(int maxTotal, int maxPerRoute) {
this.config.property(PROPERTY_MAX_TOTAL, maxTotal);
this.config.property(PROPERTY_MAX_PER_ROUTE, maxPerRoute);
return this;
}

public ClientConfig build() {
return this.config;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,50 +20,62 @@
import java.util.List;
import java.util.Map;

import org.apache.hugegraph.api.filter.CompressInterceptor;
import org.apache.hugegraph.util.E;

import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;

import org.apache.hugegraph.api.filter.CompressInterceptor;
import org.apache.hugegraph.rest.AbstractRestClient;
import org.apache.hugegraph.testutil.Whitebox;
import org.apache.hugegraph.util.E;

public class GremlinClient extends AbstractRestClient {

private final WebTarget webTarget;
/**
* GremlinClient is a client for interacting with a Gremlin server.
* It extends the AbstractJerseyRestClient and provides methods for sending GET and POST requests.
*/
public class GremlinClient extends AbstractJerseyRestClient {

public GremlinClient(String url, int timeout,
int maxTotal, int maxPerRoute) {
/**
* Constructs a GremlinClient with the specified URL, timeout, maxTotal, and maxPerRoute.
*
* @param url The URL of the Gremlin server this client will interact with.
* @param timeout The timeout for the client.
* @param maxTotal The maximum total connections for the client.
* @param maxPerRoute The maximum connections per route for the client.
*/
public GremlinClient(String url, int timeout, int maxTotal, int maxPerRoute) {
super(url, timeout, maxTotal, maxPerRoute);
this.webTarget = Whitebox.getInternalState(this, "target");
E.checkNotNull(this.webTarget, "target");
}

@Override
protected void checkStatus(Response response, Response.Status... statuses) {
// pass
}

/**
* Sends a POST request to the Gremlin server.
*
* @param auth The authorization token for the request.
* @param req The body of the request.
* @return The response from the server.
*/
public Response doPostRequest(String auth, String req) {
Entity<?> body = Entity.entity(req, MediaType.APPLICATION_JSON);
return this.webTarget.request()
.header(HttpHeaders.AUTHORIZATION, auth)
.accept(MediaType.APPLICATION_JSON)
.acceptEncoding(CompressInterceptor.GZIP)
.post(body);
return this.getWebTarget().request()
.header(HttpHeaders.AUTHORIZATION, auth)
.accept(MediaType.APPLICATION_JSON)
.acceptEncoding(CompressInterceptor.GZIP)
.post(body);
}

public Response doGetRequest(String auth,
MultivaluedMap<String, String> params) {
WebTarget target = this.webTarget;
/**
* Sends a GET request to the Gremlin server.
*
* @param auth The authorization token for the request.
* @param params The query parameters for the request.
* @return The response from the server.
*/
public Response doGetRequest(String auth, MultivaluedMap<String, String> params) {
WebTarget target = this.getWebTarget();
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
E.checkArgument(entry.getValue().size() == 1,
"Invalid query param '%s', can only accept " +
"one value, but got %s",
"Invalid query param '%s', can only accept one value, but got %s",
entry.getKey(), entry.getValue());
target = target.queryParam(entry.getKey(), entry.getValue().get(0));
}
Expand Down
Loading

0 comments on commit 644e15e

Please sign in to comment.