Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,11 @@
<sha256 value="baf7d6ea97ce606c53e11b6854ba5f2ce7ef5c24dddf0afa18d1260bd25b002c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.flatbuffers" name="flatbuffers-java" version="23.5.26">
<artifact name="flatbuffers-java-23.5.26.jar">
<sha256 value="8d10cac2ea9878896077ba437d76fdb1b9a07f55a863c560bb8a024b04103f8b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.googlejavaformat" name="google-java-format" version="1.16.0">
<artifact name="google-java-format-1.16.0.jar">
<sha256 value="0cff5d0230ba20d538f3f70b2aa68bd33f9fdc69768cde07337c563c23eb7c43" origin="Generated by Gradle"/>
Expand Down Expand Up @@ -1765,6 +1770,26 @@
<sha256 value="cd7695b3bfb6964ab71b6a0b31dad60005ae77fe502132364679aacf08f77970" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.arrow" name="arrow-format" version="15.0.0">
<artifact name="arrow-format-15.0.0.jar">
<sha256 value="e06d6cace6ecb5175972d660f6b05d090bb8997e905f9202bc8861e87e58a974" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.arrow" name="arrow-memory-core" version="15.0.0">
<artifact name="arrow-memory-core-15.0.0.jar">
<sha256 value="f22c0cb1d140ced3cd6206efee7202b3d1d471331237c8e602bbb8831a8de2a8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.arrow" name="arrow-memory-unsafe" version="15.0.0">
<artifact name="arrow-memory-unsafe-15.0.0.jar">
<sha256 value="4446ce16d5c481b7206220eae2498396e65a36504ea3e0b143873d28077d4400" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.arrow" name="arrow-vector" version="15.0.0">
<artifact name="arrow-vector-15.0.0.jar">
<sha256 value="d4f556d025b3658bd6df76adf8ce2ab3096d0efa2a81ad386de60ccba95fdf4a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.avro" name="avro" version="1.7.4">
<artifact name="avro-1.7.4.jar">
<sha256 value="a01d26e9a5ed0754e8c88dbb373fba896c57df0a0c424185767a3857855bb222" origin="Generated by Gradle"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AllPermission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -728,13 +727,14 @@ public final BootstrapCheckResult check(BootstrapContext context) {
}

boolean isAllPermissionGranted() {
final SecurityManager sm = System.getSecurityManager();
assert sm != null;
try {
sm.checkPermission(new AllPermission());
} catch (final SecurityException e) {
return false;
}
// final SecurityManager sm = System.getSecurityManager();
// assert sm != null;
// try {
// sm.checkPermission(new AllPermission());
// } catch (final SecurityException e) {
// return false;
// }
// NOCOMMIT disabled security manager
return true;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't commit this. But I spent half a day messing with the security manager and gave up. We should be able to fix this.

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ final class Security {
private Security() {}

static void setSecurityManager(@SuppressWarnings("removal") SecurityManager sm) {
System.setSecurityManager(sm);
// System.setSecurityManager(sm); NOCOMMIT why can't I give myself the reflection permission I need?
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
public class RecyclerBytesStreamOutput extends BytesStream implements Releasable {

static final VarHandle VH_BE_INT = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
static final VarHandle VH_LE_INT = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
static final VarHandle VH_BE_LONG = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.BIG_ENDIAN);
static final VarHandle VH_LE_LONG = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN);

private final ArrayList<Recycler.V<BytesRef>> pages = new ArrayList<>();
private final Recycler<BytesRef> recycler;
Expand Down Expand Up @@ -108,6 +110,17 @@ public void writeInt(int i) throws IOException {
}
}

@Override
public void writeIntLE(int i) throws IOException {
if (4 > (pageSize - currentPageOffset)) {
super.writeIntLE(i);
} else {
BytesRef currentPage = pages.get(pageIndex).v();
VH_LE_INT.set(currentPage.bytes, currentPage.offset + currentPageOffset, i);
currentPageOffset += 4;
}
}

@Override
public void writeLong(long i) throws IOException {
if (8 > (pageSize - currentPageOffset)) {
Expand All @@ -119,6 +132,17 @@ public void writeLong(long i) throws IOException {
}
}

@Override
public void writeLongLE(long i) throws IOException {
if (8 > (pageSize - currentPageOffset)) {
super.writeLongLE(i);
} else {
BytesRef currentPage = pages.get(pageIndex).v();
VH_LE_LONG.set(currentPage.bytes, currentPage.offset + currentPageOffset, i);
currentPageOffset += 8;
}
}

@Override
public void writeWithSizePrefix(Writeable writeable) throws IOException {
// TODO: do this without copying the bytes from tmp by calling writeBytes and just use the pages in tmp directly through
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,15 @@ public void writeInt(int i) throws IOException {
writeBytes(buffer, 0, 4);
}

/**
* Writes an int as four bytes, least significant bytes first.
*/
public void writeIntLE(int i) throws IOException {
final byte[] buffer = scratch.get();
ByteUtils.writeIntLE(i, buffer, 0);
writeBytes(buffer, 0, 4);
}

/**
* Writes an int in a variable-length format. Writes between one and
* five bytes. Smaller values take fewer bytes. Negative numbers
Expand Down Expand Up @@ -243,6 +252,15 @@ public void writeLong(long i) throws IOException {
writeBytes(buffer, 0, 8);
}

/**
* Writes a long as eight bytes.
*/
public void writeLongLE(long i) throws IOException {
final byte[] buffer = scratch.get();
ByteUtils.writeLongLE(i, buffer, 0);
writeBytes(buffer, 0, 8);
}

/**
* Writes a non-negative long in a variable-length format. Writes between one and ten bytes. Smaller values take fewer bytes. Negative
* numbers use ten bytes and trip assertions (if running in tests) so prefer {@link #writeLong(long)} or {@link #writeZLong(long)} for
Expand Down Expand Up @@ -441,6 +459,10 @@ public void writeDouble(double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}

public void writeDoubleLE(double v) throws IOException {
writeLongLE(Double.doubleToLongBits(v));
}

public void writeOptionalDouble(@Nullable Double v) throws IOException {
if (v == null) {
writeBoolean(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.bytes.ReleasableBytesReference;
import org.elasticsearch.common.collect.Iterators;
import org.elasticsearch.common.io.stream.BytesStream;
import org.elasticsearch.common.io.stream.RecyclerBytesStreamOutput;
import org.elasticsearch.common.recycler.Recycler;
Expand Down Expand Up @@ -242,4 +243,53 @@ public void close() {
}
};
}

static ChunkedRestResponseBody fromMany(ChunkedRestResponseBody first, Iterator<? extends ChunkedRestResponseBody> rest) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This'll want javadoc. But I think it's generally useful.

return new ChunkedRestResponseBody() {
private final String contentType = first.getResponseContentTypeString();
private ChunkedRestResponseBody current = first;

@Override
public boolean isDone() {
return current == null;
}

@Override
public ReleasableBytesReference encodeChunk(int sizeHint, Recycler<BytesRef> recycler) throws IOException {
try {
return current.encodeChunk(sizeHint, recycler);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't double checked this, but I'm worried that this'll send a chunk over the wire no matter how big the reference is. If it's less than the sizeHint we should probably give the next one a chance.

} finally {
if (current.isDone()) {
current.close();
if (false == rest.hasNext()) {
current = null;
} else {
current = rest.next();
if (false == contentType.equals(current.getResponseContentTypeString())) {
throw new IllegalArgumentException(
"content types much match but were ["
+ contentType
+ "] and ["
+ current.getResponseContentTypeString()
+ "]"
);
}
}
}
}
}

@Override
public String getResponseContentTypeString() {
return contentType;
}

@Override
public void close() {
// Close all remaining portions
// NOCOMMIT why I need Iterators.map here? silly compiler, give me compile
Releasables.closeExpectNoException(current, Releasables.wrap(() -> Iterators.map(rest, r -> r)));
}
};
}
}
23 changes: 23 additions & 0 deletions x-pack/plugin/esql/arrow/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apply plugin: 'elasticsearch.build'

dependencies {
implementation project('shim')
compileOnly project(':server')
compileOnly project(':x-pack:plugin:esql:compute')
implementation('org.apache.arrow:arrow-vector:15.0.0')
implementation('org.apache.arrow:arrow-format:15.0.0')
implementation('org.apache.arrow:arrow-memory-core:15.0.0')
implementation('com.google.flatbuffers:flatbuffers-java:23.5.26')
implementation("com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}")
implementation("com.fasterxml.jackson.core:jackson-core:${versions.jackson}")
implementation("com.fasterxml.jackson.core:jackson-databind:${versions.jackson}") // This isn't really used - but it is loaded!
implementation("org.slf4j:slf4j-api:${versions.slf4j}")
runtimeOnly "org.slf4j:slf4j-nop:${versions.slf4j}"

testImplementation project(':test:framework')
testImplementation('org.apache.arrow:arrow-memory-unsafe:15.0.0')
}

test {
jvmArgs('--add-opens=java.base/java.nio=ALL-UNNAMED')
}
14 changes: 14 additions & 0 deletions x-pack/plugin/esql/arrow/shim/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apply plugin: 'elasticsearch.build'

dependencies {
implementation project(':libs:elasticsearch-logging')
implementation('org.apache.arrow:arrow-vector:15.0.0')
implementation('org.apache.arrow:arrow-format:15.0.0')
implementation('org.apache.arrow:arrow-memory-core:15.0.0')
implementation('com.google.flatbuffers:flatbuffers-java:23.5.26')
implementation("com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}")
implementation("com.fasterxml.jackson.core:jackson-core:${versions.jackson}")
implementation("com.fasterxml.jackson.core:jackson-databind:${versions.jackson}") // This isn't really used - but it is loaded!
implementation("org.slf4j:slf4j-api:${versions.slf4j}")
runtimeOnly "org.slf4j:slf4j-nop:${versions.slf4j}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.esql.arrow.shim;

import org.apache.arrow.memory.AllocationManager;
import org.apache.arrow.memory.ArrowBuf;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.memory.DefaultAllocationManagerOption;
import org.elasticsearch.logging.LogManager;

import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
* We don't actually <strong>use</strong> Arrow's memory manager, but , arrow
* won't initialize properly unless we configure one. We configure an "empty"
* one here.
*/
public class Shim implements AllocationManager.Factory {
/**
* Initialize the Arrow shim. Arrow does some interesting reflection stuff on
* initialization. We can avoid it if we
*/
public static void init() {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arrow has some "interesting" code in the initialization. In an effort to be magic it looks around the in classpath and calls setAccessible on something. That something is public already, but the security manager still fails.

We can avoid the whole classpath scanning and reflection magic with some contained magic of our own - this stuff. But we need security manager privileges. So I moved this to it's own tiny jar.

Lastly, this replaces all the things arrow does with the Unsafe with a shim that does nothing. That's fine for how we're using it.

try {
Class.forName("org.elasticsearch.test.ESTestCase");
LogManager.getLogger(Shim.class)
.info("we're in tests, disabling the arrow shim so we can use a real apache arrow runtime for testing");
} catch (ClassNotFoundException notfound) {
LogManager.getLogger(Shim.class).debug("shimming arrow's allocation manager");
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
try {
Field field = DefaultAllocationManagerOption.class.getDeclaredField("DEFAULT_ALLOCATION_MANAGER_FACTORY");
field.setAccessible(true);
field.set(null, new Shim());
} catch (Exception e) {
throw new AssertionError("can't init arrow", e);
}
return null;
});
}
}

@Override
public AllocationManager create(BufferAllocator accountingAllocator, long size) {
throw new UnsupportedOperationException();
}

@Override
public ArrowBuf empty() {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.esql.arrow;

import org.elasticsearch.xcontent.MediaType;

import java.util.Map;
import java.util.Set;

public class ArrowFormat implements MediaType {
public static final ArrowFormat INSTANCE = new ArrowFormat();

private static final String FORMAT = "arrow";
public static final String CONTENT_TYPE = "application/arrow";
private static final String VENDOR_CONTENT_TYPE = "application/vnd.elasticsearch+arrow";

@Override
public String queryParameter() {
return FORMAT;
}

@Override
public Set<HeaderValue> headerValues() {
return Set.of(
new HeaderValue(CONTENT_TYPE, Map.of("header", "present|absent")),
new HeaderValue(VENDOR_CONTENT_TYPE, Map.of("header", "present|absent", COMPATIBLE_WITH_PARAMETER_NAME, VERSION_PATTERN))
);
}
}
Loading