Skip to content

Commit

Permalink
- ResourceDMBean now uses MethodHandles for faster access to attrs (h…
Browse files Browse the repository at this point in the history
  • Loading branch information
belaban committed Apr 17, 2024
1 parent 1b1acc8 commit 684e6b2
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 16 deletions.
54 changes: 40 additions & 14 deletions src/org/jgroups/jmx/ResourceDMBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import org.jgroups.util.Util;

import javax.management.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -91,11 +93,18 @@ public ResourceDMBean(Object instance) {
}



public MBeanInfo getMBeanInfo() {
return new MBeanInfo(obj.getClass().getCanonicalName(), "DynamicMBean", attrInfo, null, opInfo, null);
}

public void forAllAttributes(BiConsumer<String,AttributeEntry> c) {
if(c == null)
return;
for(Map.Entry<String,AttributeEntry> e: atts.entrySet()) {
c.accept(e.getKey(), e.getValue());
}
}

public Object getAttribute(String name) {
if(name == null || name.isEmpty())
throw new NullPointerException("Invalid attribute requested " + name);
Expand Down Expand Up @@ -521,10 +530,7 @@ protected boolean setNamedAttribute(Attribute attribute) {






protected static class AttributeEntry {
public static class AttributeEntry {

/** The name of the field or method. Can be different from the key in atts when name in @Property or
* @ManagedAttribute was used */
Expand All @@ -533,21 +539,23 @@ protected static class AttributeEntry {
protected Accessor getter;
protected Accessor setter;

protected AttributeEntry(String name, MBeanAttributeInfo info) {
public AttributeEntry(String name, MBeanAttributeInfo info) {
this(name, info, null, null);
}

protected AttributeEntry(String name, MBeanAttributeInfo info, Accessor getter, Accessor setter) {
public AttributeEntry(String name, MBeanAttributeInfo info, Accessor getter, Accessor setter) {
this.name=name;
this.info=info;
this.getter=getter;
this.setter=setter;
}

protected Accessor getter() {return getter;}
protected AttributeEntry getter(Accessor new_getter) {this.getter=new_getter; return this;}
protected Accessor setter() {return setter;}
protected AttributeEntry setter(Accessor new_setter) {this.setter=new_setter; return this;}
public String name() {return name;}
public MBeanAttributeInfo info() {return info;}
public Accessor getter() {return getter;}
public AttributeEntry getter(Accessor new_getter) {this.getter=new_getter; return this;}
public Accessor setter() {return setter;}
public AttributeEntry setter(Accessor new_setter) {this.setter=new_setter; return this;}


public String toString() {
Expand Down Expand Up @@ -588,21 +596,39 @@ public Object invoke(Object new_val) throws Exception {
}

public static class FieldAccessor implements Accessor {
protected final Field field;
protected final Object target;
protected final Field field;
protected final Object target;
protected static final MethodHandles.Lookup LOOKUP=MethodHandles.lookup();
protected MethodHandle mh;

public FieldAccessor(Field field, Object target) {
this.field=field;
this.target=target;
if(!field.isAccessible())
field.setAccessible(true);
try {
mh=LOOKUP.unreflectGetter(field);
}
catch(IllegalAccessException e) {
// todo: log warning?
// throw new RuntimeException(e);
}
}

public Field getField() {return field;}

public Object invoke(Object new_val) throws Exception {
if(new_val == null)
if(new_val == null) {
if(mh != null) {
try {
return mh.invoke(target);
}
catch(Throwable e) {
;
}
}
return field.get(target);
}
else {
field.set(target, new_val);
return null;
Expand Down
3 changes: 1 addition & 2 deletions src/org/jgroups/protocols/Fragmentation.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ public class Fragmentation extends Protocol {

@Property(description="The max number of bytes in a message. Larger messages will be fragmented",
type=AttributeType.BYTES)
protected int frag_size=60000;

protected int frag_size=60000;
protected LongAdder num_frags_sent=new LongAdder();
protected LongAdder num_frags_received=new LongAdder();

Expand Down
94 changes: 94 additions & 0 deletions src/org/jgroups/util/ExtractMetrics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.jgroups.util;

import org.jgroups.JChannel;
import org.jgroups.jmx.ResourceDMBean;
import org.jgroups.stack.Protocol;

import javax.management.MBeanAttributeInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

/**
* Extracts all attributes and methods annotated with {@link org.jgroups.annotations.ManagedAttribute} and returns them
* as a map of names associated with [getter-method/description tuples]. E.g. for an attribute called foo, a method
* foo() or getFoo() is searched for.
* @author Bela Ban
* @since 5.4, 5.3.6
*/
public class ExtractMetrics {
protected JChannel ch;

public static class Entry {
protected final String description;
protected final Supplier<Object> method;

protected Entry(String description, Supplier<Object> method) {
this.description=description;
this.method=method;
}

public String getDescription() {
return description;
}

public Supplier<Object> getMethod() {
return method;
}

@Override
public String toString() {
return String.format(" %s [%s]", method.get(), description);
}
}

public static Map<String,Map<String,Entry>> extract(JChannel ch) {
Map<String,Map<String,Entry>> map=new HashMap<>();
for(Protocol p: ch.stack().getProtocols()) {
map.put(p.getName(), extract(p));
}
return map;
}


public static Map<String,Entry> extract(Protocol p) {
Map<String,Entry> map=new HashMap<>();

ResourceDMBean dm=new ResourceDMBean(p);
dm.forAllAttributes((k,v) -> {
MBeanAttributeInfo info=v.info();
String descr=info != null? info.getDescription() : "n/a";
Supplier<Object> getter=() -> {
try {
return v.getter() != null? v.getter().invoke(null) : null;
}
catch(Exception e) {
System.err.printf("failed getting value for %s\n", k);
return null;
}
};
map.put(k, new Entry(descr, getter));
});

return map;
}

protected void start() throws Exception {
ch=new JChannel().connect("bla").name("X");
Map<String,Map<String,Entry>> map=extract(ch);
for(Map.Entry<String,Map<String,Entry>> e: map.entrySet()) {
System.out.printf("\n%s:\n---------------\n", e.getKey());
for(Map.Entry<String,Entry> e2: e.getValue().entrySet()) {
System.out.printf(" %s: %s\n", e2.getKey(), e2.getValue());
}
}
Util.close(ch);
}

public static void main(String[] args) throws Throwable {
new ExtractMetrics().start();

}
}


0 comments on commit 684e6b2

Please sign in to comment.