Skip to content

Commit 35f8585

Browse files
committed
[bugfix] Fix issues that stop the JMX Client from running correctly
Closes eXist-db/exist#5706
1 parent a48ffcf commit 35f8585

File tree

6 files changed

+256
-60
lines changed

6 files changed

+256
-60
lines changed

exist-core/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,12 @@
800800
<include>src/main/java/org/exist/launcher/ServiceManagerFactory.java</include>
801801
<include>src/main/java/org/exist/launcher/SplashScreen.java</include>
802802
<include>src/main/java/org/exist/launcher/WindowsServiceManager.java</include>
803+
<include>src/main/java/org/exist/management/client/JMXClient.java</include>
804+
<include>src/main/java/org/exist/management/impl/Database.java</include>
805+
<include>src/main/java/org/exist/management/impl/DatabaseMXBean.java</include>
803806
<include>src/main/java/org/exist/management/impl/ExistMBean.java</include>
807+
<include>src/main/java/org/exist/management/impl/CollectionCache.java</include>
808+
<include>src/main/java/org/exist/management/impl/CollectionCacheMXBean.java</include>
804809
<include>src/main/java/org/exist/protocolhandler/xmldb/XmldbURL.java</include>
805810
<include>src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcUpload.java</include>
806811
<include>src/main/java/org/exist/repo/ClasspathHelper.java</include>
@@ -1004,7 +1009,12 @@
10041009
<exclude>src/main/java/org/exist/launcher/LauncherWrapper.java</exclude>
10051010
<exclude>src/main/java/org/exist/launcher/SplashScreen.java</exclude>
10061011
<exclude>src/main/java/org/exist/launcher/WindowsServiceManager.java</exclude>
1012+
<exclude>src/main/java/org/exist/management/client/JMXClient.java</exclude>
1013+
<exclude>src/main/java/org/exist/management/impl/Database.java</exclude>
1014+
<exclude>src/main/java/org/exist/management/impl/DatabaseMXBean.java</exclude>
10071015
<exclude>src/main/java/org/exist/management/impl/ExistMBean.java</exclude>
1016+
<exclude>src/main/java/org/exist/management/impl/CollectionCache.java</exclude>
1017+
<exclude>src/main/java/org/exist/management/impl/CollectionCacheMXBean.java</exclude>
10081018
<exclude>src/main/java/org/exist/protocolhandler/xmldb/XmldbURL.java</exclude>
10091019
<exclude>src/main/java/org/exist/protocolhandler/xmlrpc/XmlrpcUpload.java</exclude>
10101020
<exclude>src/main/java/org/exist/repo/ClasspathHelper.java</exclude>

exist-core/src/main/java/org/exist/management/client/JMXClient.java

Lines changed: 130 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -23,12 +47,14 @@
2347

2448
import org.exist.start.CompatibleJavaVersionCheck;
2549
import org.exist.start.StartException;
50+
import org.exist.util.FileUtils;
2651
import org.exist.util.SystemExitCodes;
2752
import se.softhouse.jargo.Argument;
2853
import se.softhouse.jargo.ArgumentException;
2954
import se.softhouse.jargo.CommandLineParser;
3055
import se.softhouse.jargo.ParsedArguments;
3156

57+
import javax.annotation.Nullable;
3258
import javax.management.Attribute;
3359
import javax.management.AttributeList;
3460
import javax.management.AttributeNotFoundException;
@@ -39,6 +65,7 @@
3965
import javax.management.ObjectName;
4066
import javax.management.ReflectionException;
4167
import javax.management.openmbean.CompositeData;
68+
import javax.management.openmbean.CompositeDataSupport;
4269
import javax.management.openmbean.TabularData;
4370
import javax.management.remote.JMXConnector;
4471
import javax.management.remote.JMXConnectorFactory;
@@ -78,9 +105,9 @@ public void memoryStats() {
78105
final CompositeData composite = (CompositeData) connection.getAttribute(name, "HeapMemoryUsage");
79106
if (composite != null) {
80107
echo("\nMEMORY:");
81-
echo(String.format("Current heap: %,12d k Committed memory: %,12d k",
82-
((Long)composite.get("used")) / 1024, ((Long)composite.get("committed")) / 1024));
83-
echo(String.format("Max memory: %,12d k", ((Long)composite.get("max")) / 1024));
108+
echo(String.format("Current heap: %12s Committed memory: %12s",
109+
FileUtils.humanSize((Long)composite.get("used")), FileUtils.humanSize((Long)composite.get("committed"))));
110+
echo(String.format("Max memory: %12s", FileUtils.humanSize((Long)composite.get("max"))));
84111
}
85112
} catch (final Exception e) {
86113
error(e);
@@ -91,23 +118,24 @@ public void instanceStats() {
91118
try {
92119
echo("\nINSTANCE:");
93120
final ObjectName name = new ObjectName("org.exist.management." + instance + ":type=Database");
121+
echo(String.format("%25s: %10s", "Name", instance));
94122
final Long memReserved = (Long) connection.getAttribute(name, "ReservedMem");
95-
echo(String.format("%25s: %10d k", "Reserved memory", memReserved / 1024));
123+
echo(String.format("%25s: %10s", "Reserved memory", FileUtils.humanSize(memReserved)));
96124
final Long memCache = (Long) connection.getAttribute(name, "CacheMem");
97-
echo(String.format("%25s: %10d k", "Cache memory", memCache / 1024));
125+
echo(String.format("%25s: %10s", "Cache memory", FileUtils.humanSize(memCache)));
98126
final Long memCollCache = (Long) connection.getAttribute(name, "CollectionCacheMem");
99-
echo(String.format("%25s: %10d k", "Collection cache memory", memCollCache / 1024));
127+
echo(String.format("%25s: %10s", "Collection cache memory", FileUtils.humanSize(memCollCache)));
100128

101-
final String cols[] = { "MaxBrokers", "AvailableBrokers", "ActiveBrokers" };
129+
final String[] cols = { "MaxBrokers", "AvailableBrokers", "ActiveBrokers" };
102130
echo(String.format("\n%17s %17s %17s", cols[0], cols[1], cols[2]));
103131
final AttributeList attrs = connection.getAttributes(name, cols);
104-
final Object values[] = getValues(attrs);
105-
echo(String.format("%17d %17d %17d", values[0], values[1], values[2]));
132+
final Object[] values = getValues(attrs);
133+
echo(String.format("%17d %17d %17d", (Integer)values[0], (Integer)values[1], (Integer)values[2]));
106134

107135
final TabularData table = (TabularData) connection.getAttribute(name, "ActiveBrokersMap");
108-
if (table.size() > 0) {
136+
// if (table.size() > 0) {
109137
echo("\nCurrently active threads:");
110-
}
138+
// }
111139

112140
for (Object o : table.values()) {
113141
final CompositeData data = (CompositeData) o;
@@ -121,59 +149,100 @@ public void instanceStats() {
121149
public void cacheStats() {
122150
try {
123151
ObjectName name = new ObjectName("org.exist.management." + instance + ":type=CacheManager");
124-
String cols[] = { "MaxTotal", "CurrentSize" };
152+
String[] cols = { "MaxTotal", "CurrentSize" };
125153
AttributeList attrs = connection.getAttributes(name, cols);
126-
Object values[] = getValues(attrs);
154+
Object[] values = getValues(attrs);
127155
echo(String.format("\nCACHE [%8d pages max. / %8d pages allocated]", values[0], values[1]));
128156

129157
final Set<ObjectName> beans = connection.queryNames(new ObjectName("org.exist.management." + instance + ":type=CacheManager.Cache,*"), null);
130-
cols = new String[] {"Type", "FileName", "Size", "Used", "Hits", "Fails"};
158+
cols = new String[] {"Type", "CacheName", "Size", "Used", "Hits", "Fails"};
131159
echo(String.format("%10s %20s %10s %10s %10s %10s", cols[0], cols[1], cols[2], cols[3], cols[4], cols[5]));
132-
for (ObjectName bean : beans) {
160+
for (final ObjectName bean : beans) {
133161
name = bean;
134162
attrs = connection.getAttributes(name, cols);
135163
values = getValues(attrs);
136164
echo(String.format("%10s %20s %,10d %,10d %,10d %,10d", values[0], values[1], values[2], values[3], values[4], values[5]));
137165
}
138-
166+
139167
echo("");
140-
name = new ObjectName("org.exist.management." + instance + ":type=CollectionCacheManager");
141-
cols = new String[] { "MaxTotal", "CurrentSize" };
168+
name = new ObjectName("org.exist.management." + instance + ":type=CollectionCache");
169+
cols = new String[] { "MaxCacheSize", "Statistics" };
142170
attrs = connection.getAttributes(name, cols);
143171
values = getValues(attrs);
144-
echo(String.format("Collection Cache: %10d k max / %10d k allocated",
145-
((Long)values[0] / 1024), ((Long)values[1] / 1024)));
172+
173+
174+
echo(String.format("COLLECTION CACHE: [%10s max]", FileUtils.humanSize((Integer)values[0])));
175+
176+
cols = new String[] {"Hit Count", "Miss Count", "Load Success Count", "Load Failure Count", "Total Load Time", "Eviction Count", "Eviction Weight"};
177+
echo(String.format("%10s %20s %20s %20s %20s %20s %20s", cols[0], cols[1], cols[2], cols[3], cols[4], cols[5], cols[6]));
178+
final CompositeDataSupport statistics = (CompositeDataSupport) values[1];
179+
echo(String.format("%10d %20d %20d %20d %20d %20d %20d", (Long)statistics.get("hitCount"), (Long)statistics.get("missCount"), (Long)statistics.get("loadSuccessCount"), (Long)statistics.get("loadFailureCount"), (Long)statistics.get("totalLoadTime"), (Long)statistics.get("evictionCount"), (Long)statistics.get("evictionWeight")));
180+
146181
} catch (final Exception e) {
147182
error(e);
148183
}
149184
}
150185

151186
public void lockTable() {
152-
echo("\nList of threads currently waiting for a lock:");
187+
echo("\nList of threads attempting to acquire a lock:");
153188
echo("-----------------------------------------------");
154189
try {
155-
final TabularData table = (TabularData) connection.getAttribute(new ObjectName("org.exist.management:type=LockManager"), "WaitingThreads");
156-
for (Object o : table.values()) {
157-
final CompositeData data = (CompositeData) o;
158-
echo("Thread " + data.get("waitingThread"));
159-
echo(String.format("%20s: %s", "Lock type", data.get("lockType")));
160-
echo(String.format("%20s: %s", "Lock mode", data.get("lockMode")));
161-
echo(String.format("%20s: %s", "Lock id", data.get("id")));
162-
echo(String.format("%20s: %s", "Held by", Arrays.toString((String[]) data.get("owner"))));
163-
final String[] readers = (String[]) data.get("waitingForRead");
164-
if (readers.length > 0) {
165-
echo(String.format("%20s: %s", "Wait for read", Arrays.toString(readers)));
166-
}
167-
final String[] writers = (String[]) data.get("waitingForWrite");
168-
if (writers.length > 0) {
169-
echo(String.format("%20s: %s", "Wait for write", Arrays.toString(writers)));
170-
}
171-
}
190+
final TabularData table = (TabularData) connection.getAttribute(new ObjectName("org.exist.management." + instance + ":type=LockTable"), "Attempting");
191+
printLockTable(table);
192+
} catch (final MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException | IOException | MalformedObjectNameException e) {
193+
error(e);
194+
}
195+
196+
echo("");
197+
198+
echo("\nList of threads holding a lock:");
199+
echo("-----------------------------------------------");
200+
try {
201+
final TabularData table = (TabularData) connection.getAttribute(new ObjectName("org.exist.management." + instance + ":type=LockTable"), "Acquired");
202+
printLockTable(table);
172203
} catch (final MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException | IOException | MalformedObjectNameException e) {
173204
error(e);
174205
}
175206
}
176207

208+
private void printLockTable(final TabularData table) {
209+
for (final Object tv : table.values()) {
210+
final CompositeData data = (CompositeData) tv;
211+
212+
final String resourceUri = (String) data.get("key");
213+
echo("URI: " + resourceUri);
214+
215+
final TabularData valueData = (TabularData) data.get("value");
216+
for (final Object vdv : valueData.values()) {
217+
final CompositeData cvdv = (CompositeData) vdv;
218+
final String resourceType = (String) cvdv.get("key");
219+
echo(String.format("%20s: %s", "Lock type", resourceType));
220+
221+
final TabularData resourceData = (TabularData) cvdv.get("value");
222+
223+
for (final Object rvdv : resourceData.values()) {
224+
final CompositeData crvdv = (CompositeData) rvdv;
225+
final String lockMode = (String) crvdv.get("key");
226+
echo(String.format("%20s: %s", "Lock type", lockMode));
227+
228+
final TabularData lockData = (TabularData) crvdv.get("value");
229+
230+
for (final Object lrvdv : lockData.values()) {
231+
final CompositeData clrvdv = (CompositeData) lrvdv;
232+
final String owner = (String) clrvdv.get("key");
233+
echo(String.format("%20s: %s", "Held by", owner));
234+
235+
final CompositeData ownerData = (CompositeData) clrvdv.get("value");
236+
237+
final Integer holdCount = (Integer) ownerData.get("count");
238+
echo(String.format("%20s: %d", "Hold count", holdCount));
239+
}
240+
}
241+
242+
}
243+
}
244+
}
245+
177246
public void sanityReport() {
178247
echo("\nSanity report");
179248
echo("-----------------------------------------------");
@@ -188,12 +257,27 @@ public void sanityReport() {
188257
if (lastCheckStart != null && lastCheckEnd != null)
189258
{echo(String.format("%22s: %dms", "Check took", (lastCheckEnd.getTime() - lastCheckStart.getTime())));}
190259

191-
final TabularData table = (TabularData)
192-
connection.getAttribute(name, "Errors");
193-
for (Object o : table.values()) {
194-
final CompositeData data = (CompositeData) o;
195-
echo(String.format("%22s: %s", "Error code", data.get("errcode")));
196-
echo(String.format("%22s: %s", "Description", data.get("description")));
260+
@Nullable final Object result = connection.getAttribute(name, "Errors");
261+
if (result != null) {
262+
@Nullable final CompositeData table;
263+
if (result.getClass().isArray()) {
264+
final CompositeData[] tables = ((CompositeData[]) result);
265+
if (tables.length > 0) {
266+
table = tables[0];
267+
} else {
268+
table = null;
269+
}
270+
} else {
271+
table = (CompositeData) result;
272+
}
273+
274+
if (table != null) {
275+
for (final Object o : table.values()) {
276+
final CompositeData data = (CompositeData) o;
277+
echo(String.format("%22s: %s", "Error code", data.get("errcode")));
278+
echo(String.format("%22s: %s", "Description", data.get("description")));
279+
}
280+
}
197281
}
198282
} catch (final MBeanException | AttributeNotFoundException | InstanceNotFoundException | ReflectionException | IOException | MalformedObjectNameException e) {
199283
error(e);
@@ -230,10 +314,10 @@ public void jobReport() {
230314
}
231315
}
232316

233-
private Object[] getValues(AttributeList attribs) {
317+
private Object[] getValues(final AttributeList attribs) {
234318
final Object[] v = new Object[attribs.size()];
235319
for (int i = 0; i < attribs.size(); i++) {
236-
v[i] = ((Attribute)attribs.get(i)).getValue();
320+
v[i] = ((Attribute) attribs.get(i)).getValue();
237321
}
238322
return v;
239323
}
@@ -256,17 +340,14 @@ private void error(Exception e) {
256340
/* connection arguments */
257341
private static final Argument<String> addressArg = stringArgument("-a", "--address")
258342
.description("RMI address of the server")
259-
.required()
260343
.defaultValue("localhost")
261344
.build();
262345
private static final Argument<Integer> portArg = integerArgument("-p", "--port")
263346
.description("RMI port of the server")
264-
.required()
265347
.defaultValue(DEFAULT_PORT)
266348
.build();
267349
private static final Argument<String> instanceArg = stringArgument("-i", "--instance")
268350
.description("The ID of the database instance to connect to")
269-
.required()
270351
.defaultValue("exist")
271352
.build();
272353
private static final Argument<Integer> waitArg = integerArgument("-w", "--wait")

exist-core/src/main/java/org/exist/management/impl/CollectionCache.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -19,7 +43,6 @@
1943
* License along with this library; if not, write to the Free Software
2044
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2145
*/
22-
2346
package org.exist.management.impl;
2447

2548
import org.exist.storage.BrokerPool;
@@ -58,6 +81,11 @@ public String getInstanceId() {
5881
return instance.getId();
5982
}
6083

84+
@Override
85+
public int getMaxCacheSize() {
86+
return instance.getCollectionsCache().getMaxCacheSize();
87+
}
88+
6189
@Override
6290
public org.exist.collections.CollectionCache.Statistics getStatistics() {
6391
return instance.getCollectionsCache().getStatistics();

0 commit comments

Comments
 (0)