diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java index aa72724b93029..7b7e8d25f392d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java @@ -93,12 +93,12 @@ public FunctionRef(PainlessLookup painlessLookup, Class expected, String type * @param numCaptures number of captured arguments */ public FunctionRef(Class expected, PainlessMethod interfaceMethod, PainlessMethod delegateMethod, int numCaptures) { - MethodType delegateMethodType = delegateMethod.getMethodType(); + MethodType delegateMethodType = delegateMethod.methodType; interfaceMethodName = interfaceMethod.name; factoryMethodType = MethodType.methodType(expected, delegateMethodType.dropParameterTypes(numCaptures, delegateMethodType.parameterCount())); - interfaceMethodType = interfaceMethod.getMethodType().dropParameterTypes(0, 1); + interfaceMethodType = interfaceMethod.methodType.dropParameterTypes(0, 1); // the Painless$Script class can be inferred if owner is null if (delegateMethod.target == null) { @@ -142,7 +142,7 @@ public FunctionRef(Class expected, interfaceMethodName = interfaceMethod.name; factoryMethodType = MethodType.methodType(expected, delegateMethodType.dropParameterTypes(numCaptures, delegateMethodType.parameterCount())); - interfaceMethodType = interfaceMethod.getMethodType().dropParameterTypes(0, 1); + interfaceMethodType = interfaceMethod.methodType.dropParameterTypes(0, 1); delegateClassName = CLASS_NAME; delegateInvokeType = H_INVOKESTATIC; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java index 3675cc7cd0f20..ba48fbea734cf 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java @@ -27,6 +27,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -356,10 +357,12 @@ public void addPainlessConstructor(Class targetClass, List> typePara "[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae); } + MethodType methodType = methodHandle.type(); + painlessConstructor = painlessMethodCache.computeIfAbsent( new PainlessMethodCacheKey(targetClass, CONSTRUCTOR_NAME, typeParameters), key -> new PainlessMethod(CONSTRUCTOR_NAME, targetClass, null, void.class, typeParameters, - asmConstructor, javaConstructor.getModifiers(), methodHandle) + asmConstructor, javaConstructor.getModifiers(), methodHandle, methodType) ); painlessClassBuilder.constructors.put(painlessMethodKey, painlessConstructor); @@ -516,10 +519,12 @@ public void addPainlessMethod(Class targetClass, Class augmentedClass, Str "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae); } + MethodType methodType = methodHandle.type(); + painlessMethod = painlessMethodCache.computeIfAbsent( new PainlessMethodCacheKey(targetClass, methodName, typeParameters), key -> new PainlessMethod(methodName, targetClass, null, returnType, - typeParameters, asmMethod, javaMethod.getModifiers(), methodHandle)); + typeParameters, asmMethod, javaMethod.getModifiers(), methodHandle, methodType)); painlessClassBuilder.staticMethods.put(painlessMethodKey, painlessMethod); } else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType && @@ -557,10 +562,12 @@ public void addPainlessMethod(Class targetClass, Class augmentedClass, Str } } + MethodType methodType = methodHandle.type(); + painlessMethod = painlessMethodCache.computeIfAbsent( new PainlessMethodCacheKey(targetClass, methodName, typeParameters), key -> new PainlessMethod(methodName, targetClass, augmentedClass, returnType, - typeParameters, asmMethod, javaMethod.getModifiers(), methodHandle)); + typeParameters, asmMethod, javaMethod.getModifiers(), methodHandle, methodType)); painlessClassBuilder.methods.put(painlessMethodKey, painlessMethod); } else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType && diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java index 3321de94a267f..904cf06907fde 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java @@ -38,9 +38,10 @@ public class PainlessMethod { public final org.objectweb.asm.commons.Method method; public final int modifiers; public final MethodHandle handle; + public final MethodType methodType; public PainlessMethod(String name, Class target, Class augmentation, Class rtn, List> arguments, - org.objectweb.asm.commons.Method method, int modifiers, MethodHandle handle) { + org.objectweb.asm.commons.Method method, int modifiers, MethodHandle handle, MethodType methodType) { this.name = name; this.augmentation = augmentation; this.target = target; @@ -49,54 +50,7 @@ public PainlessMethod(String name, Class target, Class augmentation, Class this.method = method; this.modifiers = modifiers; this.handle = handle; - } - - /** - * Returns MethodType for this method. - *

- * This works even for user-defined Methods (where the MethodHandle is null). - */ - public MethodType getMethodType() { - // we have a methodhandle already (e.g. whitelisted class) - // just return its type - if (handle != null) { - return handle.type(); - } - // otherwise compute it - final Class params[]; - final Class returnValue; - if (augmentation != null) { - // static method disguised as virtual/interface method - params = new Class[1 + arguments.size()]; - params[0] = augmentation; - for (int i = 0; i < arguments.size(); i++) { - params[i + 1] = PainlessLookupUtility.typeToJavaType(arguments.get(i)); - } - returnValue = PainlessLookupUtility.typeToJavaType(rtn); - } else if (Modifier.isStatic(modifiers)) { - // static method: straightforward copy - params = new Class[arguments.size()]; - for (int i = 0; i < arguments.size(); i++) { - params[i] = PainlessLookupUtility.typeToJavaType(arguments.get(i)); - } - returnValue = PainlessLookupUtility.typeToJavaType(rtn); - } else if ("".equals(name)) { - // constructor: returns the owner class - params = new Class[arguments.size()]; - for (int i = 0; i < arguments.size(); i++) { - params[i] = PainlessLookupUtility.typeToJavaType(arguments.get(i)); - } - returnValue = target; - } else { - // virtual/interface method: add receiver class - params = new Class[1 + arguments.size()]; - params[0] = target; - for (int i = 0; i < arguments.size(); i++) { - params[i + 1] = PainlessLookupUtility.typeToJavaType(arguments.get(i)); - } - returnValue = PainlessLookupUtility.typeToJavaType(rtn); - } - return MethodType.methodType(returnValue, params); + this.methodType = methodType; } public void write(MethodWriter writer) { @@ -118,7 +72,7 @@ public void write(MethodWriter writer) { // method since java 8 did not check, but java 9 and 10 do if (Modifier.isInterface(clazz.getModifiers())) { writer.visitMethodInsn(Opcodes.INVOKESTATIC, - type.getInternalName(), name, getMethodType().toMethodDescriptorString(), true); + type.getInternalName(), name, methodType.toMethodDescriptorString(), true); } else { writer.invokeStatic(type, method); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java index 7c243e296c7e3..600ca95504ac6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java @@ -145,9 +145,11 @@ void generateSignature(PainlessLookup painlessLookup) { } } + int modifiers = Modifier.STATIC | Modifier.PRIVATE; org.objectweb.asm.commons.Method method = new org.objectweb.asm.commons.Method(name, MethodType.methodType( PainlessLookupUtility.typeToJavaType(rtnType), paramClasses).toMethodDescriptorString()); - this.method = new PainlessMethod(name, null, null, rtnType, paramTypes, method, Modifier.STATIC | Modifier.PRIVATE, null); + MethodType methodType = MethodType.methodType(PainlessLookupUtility.typeToJavaType(rtnType), paramClasses); + this.method = new PainlessMethod(name, null, null, rtnType, paramTypes, method, modifiers, null, methodType); } @Override diff --git a/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java b/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java index eaf9b7ee3e3bb..823e1f079ba70 100644 --- a/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java +++ b/server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java @@ -2392,9 +2392,7 @@ public void testDocStats() throws IOException { indexShard = newStartedShard( Settings.builder().put(IndexSettings.INDEX_SOFT_DELETES_RETENTION_OPERATIONS_SETTING.getKey(), 0).build()); final long numDocs = randomIntBetween(2, 32); // at least two documents so we have docs to delete - // Delete at least numDocs/10 documents otherwise the number of deleted docs will be below 10% - // and forceMerge will refuse to expunge deletes - final long numDocsToDelete = randomIntBetween((int) Math.ceil(Math.nextUp(numDocs / 10.0)), Math.toIntExact(numDocs)); + final long numDocsToDelete = randomLongBetween(1, numDocs); for (int i = 0; i < numDocs; i++) { final String id = Integer.toString(i); indexDoc(indexShard, "_doc", id); @@ -2460,7 +2458,6 @@ public void testDocStats() throws IOException { // merge them away final ForceMergeRequest forceMergeRequest = new ForceMergeRequest(); - forceMergeRequest.onlyExpungeDeletes(randomBoolean()); forceMergeRequest.maxNumSegments(1); indexShard.forceMerge(forceMergeRequest); diff --git a/server/src/test/java/org/elasticsearch/indices/flush/FlushIT.java b/server/src/test/java/org/elasticsearch/indices/flush/FlushIT.java index bdd01e88ccad4..4483ce0d60642 100644 --- a/server/src/test/java/org/elasticsearch/indices/flush/FlushIT.java +++ b/server/src/test/java/org/elasticsearch/indices/flush/FlushIT.java @@ -286,7 +286,6 @@ public void testSyncedFlushSkipOutOfSyncReplicas() throws Exception { assertThat(fullResult.successfulShards(), equalTo(numberOfReplicas + 1)); } - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/32436") public void testDoNotRenewSyncedFlushWhenAllSealed() throws Exception { internalCluster().ensureAtLeastNumDataNodes(between(2, 3)); final int numberOfReplicas = internalCluster().numDataNodes() - 1; @@ -311,7 +310,7 @@ public void testDoNotRenewSyncedFlushWhenAllSealed() throws Exception { // Shards were updated, renew synced flush. final int moreDocs = between(1, 10); for (int i = 0; i < moreDocs; i++) { - index("test", "doc", Integer.toString(i)); + index("test", "doc", "more-" + i); } final ShardsSyncedFlushResult thirdSeal = SyncedFlushUtil.attemptSyncedFlush(logger, internalCluster(), shardId); assertThat(thirdSeal.successfulShards(), equalTo(numberOfReplicas + 1));