This is an automated email from the ASF dual-hosted git repository.
xiangfu0 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new b1da55bfdba Upgrade Reactor Netty security dependencies and preserve
transport behavior (#19828)
b1da55bfdba is described below
commit b1da55bfdba58d62ac1c42e5f1eb07698c37a863
Author: Xiang Fu <[email protected]>
AuthorDate: Wed Oct 14 16:35:47 2026 -0700
Upgrade Reactor Netty security dependencies and preserve transport behavior
(#19828)
* Upgrade Reactor Netty and preserve transport lifecycle behavior
* Use the supported Arrow allocator with Netty 4.2
* Update Netty to 4.2.19 and clarify shutdown registration ordering
Use the latest published 4.2 patch, format the TLS builder chain, and
explain why accepted channels are registered before checking shutdown.
A pre-registration-only check could miss a concurrent shutdown sweep.
Reproduce the ordering race: initialize a channel before shutdown sets
the flag, then register it after the shutdown channel sweep. Keeping the
post-registration check closes this late channel. No lifecycle change
or new test/benchmark is needed.
* Preserve shared Arrow memory limits with Netty 4.2
Reproduction: an Arrow response can exceed a 1 MiB direct-memory ceiling
with the unsafe backend. Preserve caller limits while using the paired shared
allocation factory; release partially allocated encoder vectors on failure.
* Fix ZooKeeper hostname policy with JDK TLS bootstrap
Reproduction: ZooKeeper 3.9.6 with Netty 4.2.19 rejects a trusted
mismatched peer even when zookeeper.ssl.hostnameVerification=false. Preserve
that bootstrap policy through the supported JDK supplier, retaining enabled
verification and custom supplier ownership.
* Consolidate ZooKeeper TLS bootstrap at client creation
* Preserve ZooKeeper TLS bootstrap and cipher compatibility
---
.../apache/pinot/client/DynamicBrokerSelector.java | 2 +
pinot-common/pom.xml | 2 +-
.../response/encoder/ArrowResponseEncoder.java | 25 ++-
.../apache/pinot/common/utils/ArrowAllocators.java | 143 ++++++++++++++
.../pinot/common/utils/ServiceStartableUtils.java | 2 +
.../pinot/common/utils/helix/HelixHelper.java | 11 ++
.../apache/pinot/common/utils/tls/TlsUtils.java | 7 +-
.../utils/tls/ZooKeeperSslContextSupplier.java | 77 ++++++++
.../pinot/common/utils/ArrowAllocatorsTest.java | 137 ++++++++++++++
.../utils/tls/ZooKeeperSslContextSupplierTest.java | 209 +++++++++++++++++++++
.../helix/core/util/HelixSetupUtils.java | 2 +
.../apache/pinot/core/transport/QueryServer.java | 11 ++
.../pinot-input-format/pinot-arrow/pom.xml | 7 +-
.../inputformat/arrow/ArrowMessageDecoder.java | 3 +-
.../inputformat/arrow/ArrowRecordReader.java | 3 +-
.../inputformat/arrow/BatchedArrowFileSource.java | 3 +-
.../server/predownload/PredownloadZKClient.java | 2 +
.../org/apache/pinot/tools/PinotToolLauncher.java | 2 +
.../pinot/tools/admin/PinotAdministrator.java | 2 +
.../pinot/tools/perf/PerfBenchmarkDriver.java | 5 +
pom.xml | 2 +-
21 files changed, 646 insertions(+), 11 deletions(-)
diff --git
a/pinot-clients/pinot-java-client/src/main/java/org/apache/pinot/client/DynamicBrokerSelector.java
b/pinot-clients/pinot-java-client/src/main/java/org/apache/pinot/client/DynamicBrokerSelector.java
index 5c8622149ba..f4cf5c03b04 100644
---
a/pinot-clients/pinot-java-client/src/main/java/org/apache/pinot/client/DynamicBrokerSelector.java
+++
b/pinot-clients/pinot-java-client/src/main/java/org/apache/pinot/client/DynamicBrokerSelector.java
@@ -33,6 +33,7 @@ import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.BytesPushThroughSerializer;
import org.apache.pinot.client.utils.BrokerSelectorUtils;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -68,6 +69,7 @@ public class DynamicBrokerSelector implements BrokerSelector,
IZkDataListener {
@VisibleForTesting
protected ZkClient getZkClient(String zkServers) {
+ ZooKeeperSslContextSupplier.initialize();
return new ZkClient(zkServers);
}
diff --git a/pinot-common/pom.xml b/pinot-common/pom.xml
index 050a315bec7..0c5fc3b1494 100644
--- a/pinot-common/pom.xml
+++ b/pinot-common/pom.xml
@@ -201,7 +201,7 @@
</dependency>
<dependency>
<groupId>org.apache.arrow</groupId>
- <artifactId>arrow-memory-netty</artifactId>
+ <artifactId>arrow-memory-unsafe</artifactId>
</dependency>
<dependency>
diff --git
a/pinot-common/src/main/java/org/apache/pinot/common/response/encoder/ArrowResponseEncoder.java
b/pinot-common/src/main/java/org/apache/pinot/common/response/encoder/ArrowResponseEncoder.java
index 4fb37bb9776..6b2e9926528 100644
---
a/pinot-common/src/main/java/org/apache/pinot/common/response/encoder/ArrowResponseEncoder.java
+++
b/pinot-common/src/main/java/org/apache/pinot/common/response/encoder/ArrowResponseEncoder.java
@@ -46,12 +46,13 @@ import org.apache.arrow.vector.types.pojo.FieldType;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.arrow.vector.util.JsonStringArrayList;
import org.apache.pinot.common.response.broker.ResultTable;
+import org.apache.pinot.common.utils.ArrowAllocators;
import org.apache.pinot.common.utils.DataSchema;
import org.apache.pinot.spi.utils.MapUtils;
public class ArrowResponseEncoder implements ResponseEncoder {
- private static final RootAllocator ALLOCATOR = new
RootAllocator(Long.MAX_VALUE);
+ private static final RootAllocator ALLOCATOR =
ArrowAllocators.newRootAllocator(Long.MAX_VALUE);
@Override
public byte[] encodeResultTable(ResultTable resultTable, int startRow, int
length)
@@ -69,8 +70,26 @@ public class ArrowResponseEncoder implements ResponseEncoder
{
private VectorSchemaRoot createVectorSchemaRoot(ResultTable resultTable,
DataSchema schema, int startRow,
int length) {
- List<Field> fields = new ArrayList<>();
List<FieldVector> vectors = new ArrayList<>();
+ try {
+ return createVectorSchemaRoot(resultTable, schema, startRow, length,
vectors);
+ } catch (RuntimeException | Error e) {
+ for (FieldVector vector : vectors) {
+ try {
+ vector.close();
+ } catch (RuntimeException | Error closeFailure) {
+ if (closeFailure != e) {
+ e.addSuppressed(closeFailure);
+ }
+ }
+ }
+ throw e;
+ }
+ }
+
+ private VectorSchemaRoot createVectorSchemaRoot(ResultTable resultTable,
DataSchema schema, int startRow,
+ int length, List<FieldVector> vectors) {
+ List<Field> fields = new ArrayList<>();
int numColumns = schema.getColumnNames().length; // assuming getter
returns String[]
// Create an Arrow Field and vector for each column based on its type.
@@ -196,8 +215,8 @@ public class ArrowResponseEncoder implements
ResponseEncoder {
throw new UnsupportedOperationException("Unsupported column type: "
+ colType);
}
fields.add(field);
- vector.allocateNew();
vectors.add(vector);
+ vector.allocateNew();
}
// Determine the actual end row.
diff --git
a/pinot-common/src/main/java/org/apache/pinot/common/utils/ArrowAllocators.java
b/pinot-common/src/main/java/org/apache/pinot/common/utils/ArrowAllocators.java
new file mode 100644
index 00000000000..d3ef1f2d9ec
--- /dev/null
+++
b/pinot-common/src/main/java/org/apache/pinot/common/utils/ArrowAllocators.java
@@ -0,0 +1,143 @@
+/**
+ * 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.utils;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.util.internal.PlatformDependent;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.annotation.Nullable;
+import org.apache.arrow.memory.AllocationManager;
+import org.apache.arrow.memory.ArrowBuf;
+import org.apache.arrow.memory.BufferAllocator;
+import org.apache.arrow.memory.OutOfMemoryException;
+import org.apache.arrow.memory.ReferenceManager;
+import org.apache.arrow.memory.RootAllocator;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+
+/// Creates Arrow allocators with a shared allocation budget and Netty-backed,
int-sized buffers.
+///
+/// The budget uses Netty's existing direct-memory ceiling. Int-sized
allocations also participate in
+/// Netty's direct-memory counter, preserving the limit shared with transport
buffers without relying
+/// on Arrow 19's private Netty buffer casts. Larger allocations retain
Arrow's raw-memory path but
+/// now count against the shared Arrow budget; that path is separate from
Netty's counter.
+///
+/// Callers still own their root allocator and retain their existing
per-allocator limit. Children
+/// inherit the allocation manager. Allocations through other factories or
native Arrow libraries
+/// are outside this budget.
+public final class ArrowAllocators {
+ private static final long MAX_ALLOCATION =
PlatformDependent.maxDirectMemory();
+ private static final AtomicLong ALLOCATED_MEMORY = new AtomicLong();
+ private static final ArrowBuf EMPTY_BUFFER = new
ArrowBuf(ReferenceManager.NO_OP, null, 0, 0);
+ private static final AllocationManager.Factory ALLOCATION_MANAGER_FACTORY =
new AllocationManager.Factory() {
+ @Override
+ public AllocationManager create(BufferAllocator allocator, long size) {
+ reserve(size);
+ try {
+ return new NettyAllocationManager(allocator, size);
+ } catch (RuntimeException | Error e) {
+ ALLOCATED_MEMORY.addAndGet(-size);
+ if (e instanceof OutOfMemoryError) {
+ throw new OutOfMemoryException("Failure allocating buffer.", e);
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public ArrowBuf empty() {
+ return EMPTY_BUFFER;
+ }
+ };
+
+ private ArrowAllocators() {
+ }
+
+ /// Creates a caller-owned root with the supplied accounting limit and the
shared physical allocation budget.
+ public static RootAllocator newRootAllocator(long maxAllocation) {
+ return new
RootAllocator(RootAllocator.configBuilder().maxAllocation(maxAllocation)
+ .allocationManagerFactory(ALLOCATION_MANAGER_FACTORY).build());
+ }
+
+ private static void reserve(long size) {
+ checkArgument(size >= 0, "Allocation size must be non-negative: %s", size);
+ long allocated;
+ do {
+ allocated = ALLOCATED_MEMORY.get();
+ if (size > MAX_ALLOCATION - allocated) {
+ throw new OutOfMemoryException("Arrow allocation of " + size + " bytes
exceeds the shared limit of "
+ + MAX_ALLOCATION + " bytes (already allocated: " + allocated +
").");
+ }
+ } while (!ALLOCATED_MEMORY.compareAndSet(allocated, allocated + size));
+ }
+
+ @VisibleForTesting
+ static long getAllocatedMemory() {
+ return ALLOCATED_MEMORY.get();
+ }
+
+ /// Owns one physical allocation until the final Arrow reference is released.
+ private static final class NettyAllocationManager extends AllocationManager {
+ private final long _size;
+ private final long _address;
+ @Nullable
+ private final ByteBuf _buffer;
+
+ private NettyAllocationManager(BufferAllocator allocator, long size) {
+ super(allocator);
+ _size = size;
+ if (size > Integer.MAX_VALUE) {
+ _buffer = null;
+ _address = PlatformDependent.allocateMemory(size);
+ } else {
+ ByteBuf buffer = PooledByteBufAllocator.DEFAULT.directBuffer((int)
size, (int) size);
+ try {
+ _address = buffer.memoryAddress();
+ } catch (RuntimeException | Error e) {
+ buffer.release();
+ throw e;
+ }
+ _buffer = buffer;
+ }
+ }
+
+ @Override
+ public long getSize() {
+ return _size;
+ }
+
+ @Override
+ protected long memoryAddress() {
+ return _address;
+ }
+
+ @Override
+ protected void release0() {
+ if (_buffer != null) {
+ _buffer.release();
+ } else {
+ PlatformDependent.freeMemory(_address);
+ }
+ ALLOCATED_MEMORY.addAndGet(-_size);
+ }
+ }
+}
diff --git
a/pinot-common/src/main/java/org/apache/pinot/common/utils/ServiceStartableUtils.java
b/pinot-common/src/main/java/org/apache/pinot/common/utils/ServiceStartableUtils.java
index a3fcb7b68ff..ff7c61a7e0b 100644
---
a/pinot-common/src/main/java/org/apache/pinot/common/utils/ServiceStartableUtils.java
+++
b/pinot-common/src/main/java/org/apache/pinot/common/utils/ServiceStartableUtils.java
@@ -27,6 +27,7 @@ import org.apache.helix.zookeeper.datamodel.ZNRecord;
import org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
import org.apache.helix.zookeeper.impl.client.ZkClient;
import org.apache.pinot.common.utils.request.RequestUtils;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.apache.pinot.segment.spi.index.ForwardIndexConfig;
import org.apache.pinot.spi.config.table.FieldConfig.CompressionCodec;
import org.apache.pinot.spi.data.FieldSpec;
@@ -56,6 +57,7 @@ public class ServiceStartableUtils {
/// - pinot.all.\* will be replaced to role specific config, e.g.
pinot.controller.\* for controllers
public static void applyClusterConfig(PinotConfiguration instanceConfig,
String zkAddress, String clusterName,
ServiceRole serviceRole) {
+ ZooKeeperSslContextSupplier.initialize();
int zkClientSessionConfig =
instanceConfig.getProperty(CommonConstants.Helix.ZkClient.ZK_CLIENT_SESSION_TIMEOUT_MS_CONFIG,
CommonConstants.Helix.ZkClient.DEFAULT_SESSION_TIMEOUT_MS);
diff --git
a/pinot-common/src/main/java/org/apache/pinot/common/utils/helix/HelixHelper.java
b/pinot-common/src/main/java/org/apache/pinot/common/utils/helix/HelixHelper.java
index 8377938ae22..e8636bea991 100644
---
a/pinot-common/src/main/java/org/apache/pinot/common/utils/helix/HelixHelper.java
+++
b/pinot-common/src/main/java/org/apache/pinot/common/utils/helix/HelixHelper.java
@@ -33,6 +33,8 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.helix.HelixAdmin;
import org.apache.helix.HelixDataAccessor;
import org.apache.helix.HelixManager;
+import org.apache.helix.HelixManagerFactory;
+import org.apache.helix.InstanceType;
import org.apache.helix.PropertyKey.Builder;
import org.apache.helix.model.ExternalView;
import org.apache.helix.model.HelixConfigScope;
@@ -46,6 +48,7 @@ import
org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
import org.apache.pinot.common.helix.ExtraInstanceConfig;
import org.apache.pinot.common.metadata.ZKMetadataProvider;
import org.apache.pinot.common.utils.config.TagNameUtils;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.apache.pinot.common.version.PinotVersion;
import org.apache.pinot.common.workload.WorkloadChangeListener;
import org.apache.pinot.spi.config.table.TableConfig;
@@ -78,6 +81,14 @@ public class HelixHelper {
public static final String BROKER_RESOURCE =
CommonConstants.Helix.BROKER_RESOURCE_INSTANCE;
+ /// Creates a ZooKeeper-backed manager with Pinot's TLS bootstrap policy
applied before construction.
+ /// Callers retain responsibility for the manager's connect/disconnect
lifecycle.
+ public static HelixManager createZkHelixManager(String clusterName, String
instanceName, InstanceType instanceType,
+ String zkAddress) {
+ ZooKeeperSslContextSupplier.initialize();
+ return HelixManagerFactory.getZKHelixManager(clusterName, instanceName,
instanceType, zkAddress);
+ }
+
public static IdealState cloneIdealState(IdealState idealState) {
return new IdealState(
(ZNRecord)
ZN_RECORD_SERIALIZER.deserialize(ZN_RECORD_SERIALIZER.serialize(idealState.getRecord())));
diff --git
a/pinot-common/src/main/java/org/apache/pinot/common/utils/tls/TlsUtils.java
b/pinot-common/src/main/java/org/apache/pinot/common/utils/tls/TlsUtils.java
index b5121befa4a..118d212dc7d 100644
--- a/pinot-common/src/main/java/org/apache/pinot/common/utils/tls/TlsUtils.java
+++ b/pinot-common/src/main/java/org/apache/pinot/common/utils/tls/TlsUtils.java
@@ -342,8 +342,11 @@ public final class TlsUtils {
SSLFactory sslFactory =
RenewableTlsUtils.createSSLFactoryAndEnableAutoRenewalWhenUsingFileStores(
tlsConfig, PinotInsecureMode::isPinotInInsecureMode);
- SslContextBuilder sslContextBuilder =
-
SslContextBuilder.forClient().sslProvider(SslProvider.valueOf(tlsConfig.getSslProvider()));
+ // Keep Pinot's existing TLS behavior: verify certificate trust without
hostname verification.
+ // Netty 4.2 enables hostname verification by default, which requires a
peer hostname.
+ SslContextBuilder sslContextBuilder = SslContextBuilder.forClient()
+ .sslProvider(SslProvider.valueOf(tlsConfig.getSslProvider()))
+ .endpointIdentificationAlgorithm(null);
sslFactory.getKeyManagerFactory().ifPresent(sslContextBuilder::keyManager);
sslFactory.getTrustManagerFactory().ifPresent(sslContextBuilder::trustManager);
diff --git
a/pinot-common/src/main/java/org/apache/pinot/common/utils/tls/ZooKeeperSslContextSupplier.java
b/pinot-common/src/main/java/org/apache/pinot/common/utils/tls/ZooKeeperSslContextSupplier.java
new file mode 100644
index 00000000000..4ef7a6eec13
--- /dev/null
+++
b/pinot-common/src/main/java/org/apache/pinot/common/utils/tls/ZooKeeperSslContextSupplier.java
@@ -0,0 +1,77 @@
+/**
+ * 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.utils.tls;
+
+import io.netty.handler.ssl.CipherSuiteConverter;
+import java.util.Properties;
+import java.util.function.Supplier;
+import javax.net.ssl.SSLContext;
+import org.apache.zookeeper.common.ClientX509Util;
+import org.apache.zookeeper.common.X509Exception.SSLContextException;
+import org.apache.zookeeper.common.ZKConfig;
+
+
+/// Preserves disabled ZooKeeper hostname verification with Netty 4.2 using
ZooKeeper's JDK context supplier hook.
+///
+/// Pinot's Helix clients use process-wide ZooKeeper TLS bootstrap properties.
Call [#initialize()] before creating
+/// these clients; existing custom suppliers retain ownership of their context
and provider. The vendor's no-argument
+/// supplier cannot consume arbitrary per-client TLS overrides, so it is
intended for these bootstrap-owned clients.
+/// Each context uses ZooKeeper's configured stores, protocol, revocation and
FIPS policy, without caching key material.
+public class ZooKeeperSslContextSupplier implements Supplier<SSLContext> {
+ /// Installs the JDK adapter only when bootstrap configuration explicitly
disables hostname verification.
+ /// Enabled verification and custom suppliers keep their existing
construction paths. TLS bootstrap configuration
+ /// must be supplied before client creation; it cannot be obtained from the
cluster being connected to.
+ public static void initialize() {
+ Properties properties = System.getProperties();
+ synchronized (properties) {
+ try (ClientX509Util util = new ClientX509Util()) {
+ ZKConfig config = new ZKConfig();
+ if (util.isServerHostnameVerificationEnabled(config)
+ || config.getProperty(util.getSslContextSupplierClassProperty())
!= null) {
+ return;
+ }
+ // The supplied JDK context needs JSSE names for ciphers previously
configured for OpenSSL.
+ String cipherSuites =
config.getProperty(util.getSslCipherSuitesProperty());
+ if (cipherSuites != null) {
+ String[] ciphers = cipherSuites.split(",", -1);
+ for (int i = 0; i < ciphers.length; i++) {
+ String javaCipher = CipherSuiteConverter.toJava(ciphers[i], "TLS");
+ if (javaCipher != null) {
+ ciphers[i] = javaCipher;
+ }
+ }
+ properties.setProperty(util.getSslCipherSuitesProperty(),
String.join(",", ciphers));
+ }
+ // ZooKeeper 3.9.6 supports supplied SSLContext instances only with
its JDK provider.
+ properties.setProperty(util.getSslProviderProperty(), "JDK");
+ properties.setProperty(util.getSslContextSupplierClassProperty(),
ZooKeeperSslContextSupplier.class.getName());
+ }
+ }
+ }
+
+ @Override
+ public SSLContext get() {
+ try (ClientX509Util util = new ClientX509Util()) {
+ // Bypass supplier loading without temporarily removing the process-wide
supplier property.
+ return util.createSSLContextAndOptionsFromConfig(new
ZKConfig()).getSSLContext();
+ } catch (SSLContextException e) {
+ throw new IllegalStateException("Unable to create the ZooKeeper TLS
context from bootstrap configuration", e);
+ }
+ }
+}
diff --git
a/pinot-common/src/test/java/org/apache/pinot/common/utils/ArrowAllocatorsTest.java
b/pinot-common/src/test/java/org/apache/pinot/common/utils/ArrowAllocatorsTest.java
new file mode 100644
index 00000000000..d56d818a111
--- /dev/null
+++
b/pinot-common/src/test/java/org/apache/pinot/common/utils/ArrowAllocatorsTest.java
@@ -0,0 +1,137 @@
+/**
+ * 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.utils;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.PooledByteBufAllocator;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+import org.apache.arrow.memory.ArrowBuf;
+import org.apache.arrow.memory.BufferAllocator;
+import org.apache.arrow.memory.OutOfMemoryException;
+import org.apache.arrow.memory.RootAllocator;
+import org.apache.pinot.common.response.broker.ResultTable;
+import org.apache.pinot.common.response.encoder.ArrowResponseEncoder;
+import org.apache.pinot.common.utils.DataSchema.ColumnDataType;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.expectThrows;
+
+
+/// Verifies allocation limits and encoder recovery in an isolated JVM.
+public class ArrowAllocatorsTest {
+ @Test
+ public void testProcessMemoryLimitAndEncoderRecovery()
+ throws Exception {
+ String classpath = System.getProperty("surefire.test.class.path",
System.getProperty("java.class.path"));
+ Process process = new
ProcessBuilder(Path.of(System.getProperty("java.home"), "bin",
"java").toString(),
+ "-Xmx64m", "-XX:MaxDirectMemorySize=1m",
"--add-opens=java.base/java.nio=ALL-UNNAMED",
+ "-Dio.netty.maxDirectMemory=1048576",
"-Dio.netty.tryReflectionSetAccessible=true",
+ "-Dio.netty.allocator.numDirectArenas=1",
"-Dio.netty.allocator.maxOrder=4", "-cp", classpath,
+ MemoryLimitProbe.class.getName()).redirectErrorStream(true).start();
+ try {
+ assertTrue(process.waitFor(30, TimeUnit.SECONDS), "Arrow memory limit
probe timed out");
+ String output = new String(process.getInputStream().readAllBytes(),
StandardCharsets.UTF_8);
+ assertEquals(process.exitValue(), 0, output);
+ } finally {
+ process.destroyForcibly();
+ }
+ }
+
+ /// Exercises the production allocator and encoder in a JVM with a bounded
direct-memory limit.
+ public static final class MemoryLimitProbe {
+ private MemoryLimitProbe() {
+ }
+
+ public static void main(String[] args)
+ throws Exception {
+ testSharedBudgetAndChildren();
+ testNettyBudgetAndRetainedReferences();
+ testEncoderRecovery();
+ }
+
+ private static void testSharedBudgetAndChildren() {
+ try (RootAllocator first =
ArrowAllocators.newRootAllocator(Long.MAX_VALUE);
+ RootAllocator second =
ArrowAllocators.newRootAllocator(Long.MAX_VALUE);
+ BufferAllocator child = first.newChildAllocator("query", 0,
Long.MAX_VALUE)) {
+ ArrowBuf firstBuffer = child.buffer(512 * 1024);
+ ArrowBuf secondBuffer = second.buffer(256 * 1024);
+ try {
+ assertEquals(ArrowAllocators.getAllocatedMemory(), 768 * 1024L);
+ expectThrows(OutOfMemoryException.class, () -> second.buffer(512 *
1024));
+ assertEquals(second.getAllocatedMemory(), 256 * 1024L);
+ firstBuffer.close();
+ firstBuffer = null;
+ try (ArrowBuf recovered = second.buffer(512 * 1024)) {
+ recovered.setLong(0, 42L);
+ assertEquals(recovered.getLong(0), 42L);
+ assertEquals(recovered.memoryAddress() % Long.BYTES, 0L);
+ }
+ expectThrows(OutOfMemoryException.class, () -> child.buffer((long)
Integer.MAX_VALUE + 1));
+ } finally {
+ if (firstBuffer != null) {
+ firstBuffer.close();
+ }
+ secondBuffer.close();
+ }
+ }
+ assertEquals(ArrowAllocators.getAllocatedMemory(), 0L);
+ }
+
+ private static void testNettyBudgetAndRetainedReferences() {
+ try (RootAllocator allocator =
ArrowAllocators.newRootAllocator(Long.MAX_VALUE)) {
+ ByteBuf occupied = PooledByteBufAllocator.DEFAULT.directBuffer(1024 *
1024, 1024 * 1024);
+ try {
+ expectThrows(OutOfMemoryException.class, () ->
allocator.buffer(4096));
+ assertEquals(allocator.getAllocatedMemory(), 0L);
+ assertEquals(ArrowAllocators.getAllocatedMemory(), 0L);
+ } finally {
+ occupied.release();
+ }
+ ArrowBuf buffer = allocator.buffer(512 * 1024);
+ buffer.getReferenceManager().retain();
+ buffer.close();
+ assertEquals(ArrowAllocators.getAllocatedMemory(), 512 * 1024L);
+ buffer.close();
+ assertEquals(ArrowAllocators.getAllocatedMemory(), 0L);
+ }
+ }
+
+ private static void testEncoderRecovery()
+ throws Exception {
+ ArrowResponseEncoder encoder = new ArrowResponseEncoder();
+ DataSchema schema = new DataSchema(new String[]{"id", "value"},
+ new ColumnDataType[]{ColumnDataType.INT, ColumnDataType.STRING});
+ ResultTable oversized = new ResultTable(schema,
Collections.singletonList(new Object[]{1,
+ "x".repeat(2 * 1024 * 1024)}));
+ expectThrows(OutOfMemoryException.class, () ->
encoder.encodeResultTable(oversized, 0, 1));
+ assertEquals(ArrowAllocators.getAllocatedMemory(), 0L);
+ ResultTable small = new ResultTable(schema,
Collections.singletonList(new Object[]{1, "ok"}));
+ byte[] encoded = encoder.encodeResultTable(small, 0, 1);
+ ResultTable decoded = encoder.decodeResultTable(encoded, 1, schema);
+ assertEquals(decoded.getRows().size(), 1);
+ assertEquals(decoded.getRows().get(0), small.getRows().get(0));
+ assertEquals(ArrowAllocators.getAllocatedMemory(), 0L);
+ }
+ }
+}
diff --git
a/pinot-common/src/test/java/org/apache/pinot/common/utils/tls/ZooKeeperSslContextSupplierTest.java
b/pinot-common/src/test/java/org/apache/pinot/common/utils/tls/ZooKeeperSslContextSupplierTest.java
new file mode 100644
index 00000000000..ace04107db2
--- /dev/null
+++
b/pinot-common/src/test/java/org/apache/pinot/common/utils/tls/ZooKeeperSslContextSupplierTest.java
@@ -0,0 +1,209 @@
+/**
+ * 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.utils.tls;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.ByteBufAllocator;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.MultiThreadIoEventLoopGroup;
+import io.netty.channel.nio.NioIoHandler;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslHandler;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.security.cert.CertificateException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import org.apache.helix.HelixManagerFactory;
+import org.apache.helix.InstanceType;
+import org.apache.pinot.common.utils.helix.HelixHelper;
+import org.apache.zookeeper.common.ClientX509Util;
+import org.apache.zookeeper.common.ZKConfig;
+import org.mockito.MockedStatic;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.mockito.Mockito.mockStatic;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+
+/// Exercises the released ZooKeeper context factory against a trusted
certificate with a mismatched peer identity.
+@Test(singleThreaded = true)
+public class ZooKeeperSslContextSupplierTest {
+ private final Map<String, String> _savedProperties = new HashMap<>();
+
+ @BeforeMethod
+ public void saveBootstrapProperties() {
+ try (ClientX509Util util = new ClientX509Util()) {
+ for (String key : new
String[]{util.getSslContextSupplierClassProperty(),
util.getSslProviderProperty(),
+ util.getSslHostnameVerificationEnabledProperty(),
util.getFipsModeProperty(),
+ util.getSslCipherSuitesProperty(),
util.getSslTruststoreLocationProperty(),
+ util.getSslTruststorePasswdProperty(),
util.getSslTruststoreTypeProperty()}) {
+ _savedProperties.put(key, System.getProperty(key));
+ }
+ System.clearProperty(util.getSslContextSupplierClassProperty());
+ }
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void restoreBootstrapProperties() {
+ _savedProperties.forEach((key, value) -> {
+ if (value == null) {
+ System.clearProperty(key);
+ } else {
+ System.setProperty(key, value);
+ }
+ });
+ _savedProperties.clear();
+ }
+
+ @Test
+ public void testCustomSupplierKeepsProviderOwnership() {
+ try (ClientX509Util util = new ClientX509Util();
+ MockedStatic<HelixManagerFactory> ignored =
mockStatic(HelixManagerFactory.class)) {
+ System.setProperty(util.getSslHostnameVerificationEnabledProperty(),
"false");
+ System.setProperty(util.getSslContextSupplierClassProperty(),
"custom.supplier");
+ System.setProperty(util.getSslProviderProperty(), "OPENSSL");
+ System.setProperty(util.getSslCipherSuitesProperty(),
"ECDHE-RSA-AES128-GCM-SHA256");
+ HelixHelper.createZkHelixManager("test-cluster", "test-instance",
InstanceType.SPECTATOR, "localhost:2181");
+
assertEquals(System.getProperty(util.getSslContextSupplierClassProperty()),
"custom.supplier");
+ assertEquals(System.getProperty(util.getSslProviderProperty()),
"OPENSSL");
+ assertEquals(System.getProperty(util.getSslCipherSuitesProperty()),
"ECDHE-RSA-AES128-GCM-SHA256");
+ }
+ }
+
+ @DataProvider
+ public Object[][] hostnamePolicies() {
+ return new Object[][]{{false, false, "OPENSSL"}, {false, true,
"OPENSSL_REFCNT"},
+ {true, false, "JDK"}, {true, true, "JDK"}};
+ }
+
+ @Test(dataProvider = "hostnamePolicies")
+ public void testConfiguredHostnamePolicy(boolean verifyHostname, boolean
fips, String provider)
+ throws Exception {
+ try (ClientX509Util util = new ClientX509Util();
+ MockedStatic<HelixManagerFactory> factory =
mockStatic(HelixManagerFactory.class)) {
+ System.setProperty(util.getSslHostnameVerificationEnabledProperty(),
Boolean.toString(verifyHostname));
+ System.setProperty(util.getFipsModeProperty(), Boolean.toString(fips));
+ System.setProperty(util.getSslProviderProperty(), provider);
+ System.setProperty(util.getSslCipherSuitesProperty(),
+ verifyHostname ? "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" :
"ECDHE-RSA-AES128-GCM-SHA256");
+ System.setProperty(util.getSslTruststoreLocationProperty(),
resourcePath("truststore.p12").toString());
+ System.setProperty(util.getSslTruststorePasswdProperty(), "changeit");
+ System.setProperty(util.getSslTruststoreTypeProperty(), "PKCS12");
+ AtomicReference<SslContext> context = new AtomicReference<>();
+ // Helix reads cloud config during manager construction. Capture that
first client's context before returning.
+ factory.when(() -> HelixManagerFactory.getZKHelixManager("test-cluster",
"test-instance", InstanceType.SPECTATOR,
+ "localhost:2181"))
+ .thenAnswer(invocation -> {
+ context.set(util.createNettySslContextForClient(new ZKConfig()));
+ return null;
+ });
+ HelixHelper.createZkHelixManager("test-cluster", "test-instance",
InstanceType.SPECTATOR, "localhost:2181");
+ SslContext clientContext = context.get();
+
+ KeyStore keys = KeyStore.getInstance("PKCS12");
+ try (InputStream stream =
Files.newInputStream(resourcePath("keystore.p12"))) {
+ keys.load(stream, "changeit".toCharArray());
+ }
+ KeyManagerFactory keyManager =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManager.init(keys, "changeit".toCharArray());
+ SSLContext serverContext = SSLContext.getInstance("TLS");
+ serverContext.init(keyManager.getKeyManagers(), null, null);
+ EventLoopGroup group = new MultiThreadIoEventLoopGroup(1,
NioIoHandler.newFactory());
+ Channel channel = null;
+ try (SSLServerSocket server = (SSLServerSocket)
serverContext.getServerSocketFactory().createServerSocket()) {
+ server.bind(new InetSocketAddress("127.0.0.1", 0));
+ server.setSoTimeout(5000);
+ int port = server.getLocalPort();
+ SslHandler ssl = clientContext.newHandler(ByteBufAllocator.DEFAULT,
"127.0.0.1", port);
+ Thread worker = new Thread(() -> {
+ try (SSLSocket socket = (SSLSocket) server.accept()) {
+ socket.setSoTimeout(5000);
+ socket.startHandshake();
+ } catch (Exception e) {
+ // An enabled-policy client rejects this deliberately mismatched
certificate and closes its connection.
+ }
+ }, "zookeeper-tls-test-server");
+ worker.setDaemon(true);
+ worker.start();
+ try {
+ channel = new
Bootstrap().group(group).channel(NioSocketChannel.class)
+ .handler(new ChannelInitializer<SocketChannel>() {
+ @Override
+ protected void initChannel(SocketChannel socket) {
+ ssl.setHandshakeTimeoutMillis(5000);
+ socket.pipeline().addLast(ssl);
+ }
+ }).connect("127.0.0.1", port).sync().channel();
+ assertTrue(ssl.handshakeFuture().await(6000), "TLS handshake did not
complete");
+ if (verifyHostname) {
+ assertFalse(ssl.handshakeFuture().isSuccess());
+ assertTrue(hasCertificateFailure(ssl.handshakeFuture().cause()),
+ "Expected a certificate rejection, not a connection or timeout
failure");
+ } else {
+ assertTrue(ssl.handshakeFuture().isSuccess(),
String.valueOf(ssl.handshakeFuture().cause()));
+ assertEquals(ssl.engine().getSession().getCipherSuite(),
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
+ }
+ } finally {
+ if (channel != null) {
+ channel.close().sync();
+ }
+ server.close();
+ worker.join(6000);
+ assertFalse(worker.isAlive(), "TLS fixture did not stop");
+ }
+ } finally {
+ group.shutdownGracefully(0, 0, TimeUnit.SECONDS).sync();
+ }
+ }
+ }
+
+ private static boolean hasCertificateFailure(Throwable failure) {
+ for (Throwable cause = failure; cause != null; cause = cause.getCause()) {
+ if (cause instanceof CertificateException) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static Path resourcePath(String name)
+ throws Exception {
+ return
Path.of(ZooKeeperSslContextSupplierTest.class.getClassLoader().getResource("tls/"
+ name).toURI());
+ }
+}
diff --git
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/util/HelixSetupUtils.java
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/util/HelixSetupUtils.java
index 832ce2346de..f5847028c1e 100644
---
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/util/HelixSetupUtils.java
+++
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/util/HelixSetupUtils.java
@@ -45,6 +45,7 @@ import
org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
import org.apache.helix.zookeeper.impl.client.ZkClient;
import org.apache.pinot.common.utils.ZkStarter;
import org.apache.pinot.common.utils.helix.LeadControllerUtils;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.apache.pinot.controller.ControllerConf;
import
org.apache.pinot.controller.helix.core.PinotHelixBrokerResourceOnlineOfflineStateModelGenerator;
import
org.apache.pinot.controller.helix.core.PinotHelixSegmentOnlineOfflineStateModelGenerator;
@@ -68,6 +69,7 @@ public class HelixSetupUtils {
/// the config doesn't already exist.
public static void setupHelixClusterWithDefaultConfigs(String zkAddress,
String clusterName,
Map<String, String> defaultConfigs) {
+ ZooKeeperSslContextSupplier.initialize();
HelixAdmin admin = new
ZKHelixAdmin.Builder().setZkAddress(zkAddress).build();
try {
if (admin.getClusters().contains(clusterName)) {
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/transport/QueryServer.java
b/pinot-core/src/main/java/org/apache/pinot/core/transport/QueryServer.java
index 51355be511f..c51fa77c5e0 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/transport/QueryServer.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/transport/QueryServer.java
@@ -62,6 +62,7 @@ public class QueryServer {
private final ChannelHandler _instanceRequestHandler;
private ServerSocketChannel _channel;
private final ConcurrentHashMap<SocketChannel, Boolean> _allChannels = new
ConcurrentHashMap<>();
+ private volatile boolean _shuttingDown;
/// Create an unsecured server instance
@@ -135,8 +136,13 @@ public class QueryServer {
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
+ // Register first so shutdown sees this channel, or the check
below closes a late registration.
_allChannels.put(ch, true);
ch.closeFuture().addListener(f -> _allChannels.remove(ch));
+ if (_shuttingDown) {
+ ch.close();
+ return;
+ }
ch.pipeline()
.addLast(ChannelHandlerFactory.getDirectOOMHandler(null,
null, null, _allChannels, _channel));
@@ -160,8 +166,13 @@ public class QueryServer {
}
public void shutDown() {
+ _shuttingDown = true;
try {
_channel.close().sync();
+ // Close accepted connections explicitly, including registrations racing
with listener shutdown.
+ for (SocketChannel channel : _allChannels.keySet()) {
+ channel.close();
+ }
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
diff --git a/pinot-plugins/pinot-input-format/pinot-arrow/pom.xml
b/pinot-plugins/pinot-input-format/pinot-arrow/pom.xml
index 71ce5a6db8f..ee9a5ec4a9c 100644
--- a/pinot-plugins/pinot-input-format/pinot-arrow/pom.xml
+++ b/pinot-plugins/pinot-input-format/pinot-arrow/pom.xml
@@ -36,6 +36,11 @@
</properties>
<dependencies>
+ <dependency>
+ <groupId>org.apache.pinot</groupId>
+ <artifactId>pinot-common</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.apache.arrow</groupId>
<artifactId>arrow-compression</artifactId>
@@ -50,7 +55,7 @@
</dependency>
<dependency>
<groupId>org.apache.arrow</groupId>
- <artifactId>arrow-memory-netty</artifactId>
+ <artifactId>arrow-memory-unsafe</artifactId>
</dependency>
<dependency>
<groupId>org.apache.arrow</groupId>
diff --git
a/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowMessageDecoder.java
b/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowMessageDecoder.java
index dfd80262b2d..d153e26b8b6 100644
---
a/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowMessageDecoder.java
+++
b/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowMessageDecoder.java
@@ -31,6 +31,7 @@ import javax.annotation.Nullable;
import org.apache.arrow.memory.RootAllocator;
import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.ipc.ArrowStreamReader;
+import org.apache.pinot.common.utils.ArrowAllocators;
import org.apache.pinot.spi.data.readers.GenericRow;
import org.apache.pinot.spi.data.readers.RecordExtractorConfig;
import org.apache.pinot.spi.plugin.PluginManager;
@@ -84,7 +85,7 @@ public class ArrowMessageDecoder implements
StreamMessageDecoder<byte[]> {
// Initialize Arrow allocator with configurable memory limit
long allocatorLimit =
Long.parseLong(props.getOrDefault(ARROW_ALLOCATOR_LIMIT,
DEFAULT_ALLOCATOR_LIMIT));
- _allocator = new RootAllocator(allocatorLimit);
+ _allocator = ArrowAllocators.newRootAllocator(allocatorLimit);
LOGGER.info("Initialized ArrowMessageDecoder for topic: {} with allocator
limit: {} bytes", topicName,
allocatorLimit);
diff --git
a/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowRecordReader.java
b/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowRecordReader.java
index dbd453201fb..91b0278128b 100644
---
a/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowRecordReader.java
+++
b/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/ArrowRecordReader.java
@@ -26,6 +26,7 @@ import javax.annotation.Nullable;
import org.apache.arrow.memory.RootAllocator;
import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.ipc.ArrowFileReader;
+import org.apache.pinot.common.utils.ArrowAllocators;
import org.apache.pinot.spi.data.readers.GenericRow;
import org.apache.pinot.spi.data.readers.RecordReader;
import org.apache.pinot.spi.data.readers.RecordReaderConfig;
@@ -56,7 +57,7 @@ public class ArrowRecordReader implements RecordReader {
}
_extractor.init(fieldsToRead, extractorConfig);
_dataFile = dataFile;
- _allocator = new RootAllocator(allocatorLimit);
+ _allocator = ArrowAllocators.newRootAllocator(allocatorLimit);
openFile();
}
diff --git
a/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/BatchedArrowFileSource.java
b/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/BatchedArrowFileSource.java
index fab615b7394..e67fc22433e 100644
---
a/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/BatchedArrowFileSource.java
+++
b/pinot-plugins/pinot-input-format/pinot-arrow/src/main/java/org/apache/pinot/plugin/inputformat/arrow/BatchedArrowFileSource.java
@@ -39,6 +39,7 @@ import org.apache.arrow.vector.ipc.ArrowFileReader;
import org.apache.arrow.vector.ipc.message.ArrowBlock;
import org.apache.arrow.vector.types.pojo.DictionaryEncoding;
import org.apache.arrow.vector.types.pojo.Field;
+import org.apache.pinot.common.utils.ArrowAllocators;
/// Reads an Apache Arrow IPC file **one record batch at a time** through the
seekable
@@ -76,7 +77,7 @@ final class BatchedArrowFileSource implements Closeable {
BatchedArrowFileSource(File dataFile, long allocatorLimit, boolean
extractRawTimeValues)
throws IOException {
- _allocator = new RootAllocator(allocatorLimit);
+ _allocator = ArrowAllocators.newRootAllocator(allocatorLimit);
_extractRawTimeValues = extractRawTimeValues;
boolean initialized = false;
try {
diff --git
a/pinot-server/src/main/java/org/apache/pinot/server/predownload/PredownloadZKClient.java
b/pinot-server/src/main/java/org/apache/pinot/server/predownload/PredownloadZKClient.java
index 5defca1d3b1..31da2e1eee7 100644
---
a/pinot-server/src/main/java/org/apache/pinot/server/predownload/PredownloadZKClient.java
+++
b/pinot-server/src/main/java/org/apache/pinot/server/predownload/PredownloadZKClient.java
@@ -41,6 +41,7 @@ import
org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
import org.apache.helix.zookeeper.impl.factory.SharedZkClientFactory;
import org.apache.pinot.common.metadata.ZKMetadataProvider;
import org.apache.pinot.common.metadata.segment.SegmentZKMetadata;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.apache.pinot.spi.config.instance.InstanceDataManagerConfig;
import org.apache.pinot.spi.config.table.TableConfig;
import org.apache.pinot.spi.data.Schema;
@@ -71,6 +72,7 @@ public class PredownloadZKClient implements AutoCloseable {
}
public void start() {
+ ZooKeeperSslContextSupplier.initialize();
RealmAwareZkClient.RealmAwareZkClientConfig config = new
RealmAwareZkClient.RealmAwareZkClientConfig();
config.setConnectInitTimeout(ZK_CONNECTION_TIMEOUT_MS);
config.setZkSerializer(new ZNRecordSerializer());
diff --git
a/pinot-tools/src/main/java/org/apache/pinot/tools/PinotToolLauncher.java
b/pinot-tools/src/main/java/org/apache/pinot/tools/PinotToolLauncher.java
index b1c27a9b90d..171f9268011 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/PinotToolLauncher.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/PinotToolLauncher.java
@@ -20,6 +20,7 @@ package org.apache.pinot.tools;
import java.util.HashMap;
import java.util.Map;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.apache.pinot.spi.plugin.PluginManager;
import org.apache.pinot.tools.filesystem.PinotFSBenchmarkRunner;
import org.apache.pinot.tools.perf.PerfBenchmarkRunner;
@@ -34,6 +35,7 @@ public class PinotToolLauncher {
private static final Map<String, Command> SUBCOMMAND_MAP = new HashMap<>();
static {
+ ZooKeeperSslContextSupplier.initialize();
SUBCOMMAND_MAP.put("UpdateSegmentState", new UpdateSegmentState());
SUBCOMMAND_MAP.put("AutoAddInvertedIndex", new AutoAddInvertedIndexTool());
SUBCOMMAND_MAP.put("ValidateTableRetention", new ValidateTableRetention());
diff --git
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/PinotAdministrator.java
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/PinotAdministrator.java
index 8a2c8edcf39..e2848510650 100644
---
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/PinotAdministrator.java
+++
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/PinotAdministrator.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.pinot.common.Utils;
import org.apache.pinot.common.utils.tls.JvmDefaultSslContext;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.apache.pinot.spi.plugin.PluginManager;
import org.apache.pinot.tools.Command;
import org.apache.pinot.tools.admin.command.AddSchemaCommand;
@@ -94,6 +95,7 @@ public class PinotAdministrator {
private static final Map<String, Command> SUBCOMMAND_MAP = new HashMap<>();
static {
+ ZooKeeperSslContextSupplier.initialize();
JvmDefaultSslContext.initDefaultSslContext();
SUBCOMMAND_MAP.put("QuickStart", new QuickStartCommand());
SUBCOMMAND_MAP.put("OperateClusterConfig", new
OperateClusterConfigCommand());
diff --git
a/pinot-tools/src/main/java/org/apache/pinot/tools/perf/PerfBenchmarkDriver.java
b/pinot-tools/src/main/java/org/apache/pinot/tools/perf/PerfBenchmarkDriver.java
index 3a500b25e9a..a4f12c0e6a3 100644
---
a/pinot-tools/src/main/java/org/apache/pinot/tools/perf/PerfBenchmarkDriver.java
+++
b/pinot-tools/src/main/java/org/apache/pinot/tools/perf/PerfBenchmarkDriver.java
@@ -46,6 +46,7 @@ import
org.apache.helix.tools.ClusterVerifiers.StrictMatchExternalViewVerifier;
import org.apache.pinot.broker.broker.helix.HelixBrokerStarter;
import org.apache.pinot.common.auth.AuthProviderUtils;
import org.apache.pinot.common.utils.ZkStarter;
+import org.apache.pinot.common.utils.tls.ZooKeeperSslContextSupplier;
import org.apache.pinot.controller.ControllerConf;
import org.apache.pinot.controller.ControllerStarter;
import org.apache.pinot.controller.helix.core.PinotHelixResourceManager;
@@ -71,6 +72,10 @@ public class PerfBenchmarkDriver {
private static final long BROKER_TIMEOUT_MS = 60_000L;
private static final String BROKER_QUERY_PATH = "/query/sql";
+ static {
+ ZooKeeperSslContextSupplier.initialize();
+ }
+
private final PerfBenchmarkDriverConf _conf;
private final String _zkAddress;
private final String _clusterName;
diff --git a/pom.xml b/pom.xml
index f96881cdbdd..8f32dfdcff5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -218,7 +218,7 @@
<libthrift.version>0.25.0</libthrift.version>
<log4j.version>2.26.1</log4j.version>
<slf4j.version>2.0.20</slf4j.version>
- <netty.version>4.1.139.Final</netty.version>
+ <netty.version>4.2.19.Final</netty.version>
<reactor-netty.version>1.3.7</reactor-netty.version>
<reactor-core.version>3.8.7</reactor-core.version>
<reactivestreams.version>1.0.4</reactivestreams.version>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]