import org.apache.jackrabbit.core.cache.CacheManager;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.jackrabbit.core.config.RepositoryConfigurationParser;
+import org.apache.jackrabbit.stats.RepositoryStatisticsImpl;
import org.argeo.ArgeoException;
import org.argeo.cms.CmsException;
import org.argeo.jackrabbit.JackrabbitWrapper;
ArgeoJcrConstants {
private static Log log = LogFactory.getLog(JackrabbitNode.class);
- @SuppressWarnings("unused")
private RepositoryContext repositoryContext;
private ServiceRegistration<Repository> repositoryReg;
((RepositoryImpl) getRepository()).shutdown();
}
- Dictionary<String, ?> getDefaults() {
- return KernelUtils.asDictionary(getClass().getClassLoader(),
- "/org/argeo/cms/internal/kernel/jackrabbit-node.properties");
+ RepositoryStatisticsImpl getRepositoryStatistics() {
+ return repositoryContext.getRepositoryStatistics();
}
+ // Dictionary<String, ?> getDefaults() {
+ // return KernelUtils.asDictionary(getClass().getClassLoader(),
+ // "/org/argeo/cms/internal/kernel/jackrabbit-node.properties");
+ // }
+
private RepositoryConfig getConfiguration(JackrabbitNodeType type,
Hashtable<String, Object> vars) throws RepositoryException {
ClassLoader cl = getClass().getClassLoader();
private final BundleContext bundleContext = Activator.getBundleContext();
- private JackrabbitNode node;
- private OsgiJackrabbitRepositoryFactory repositoryFactory;
- private NodeSecurity nodeSecurity;
- private NodeHttp nodeHttp;
+ ThreadGroup threadGroup = new ThreadGroup(Kernel.class.getSimpleName());
+ JackrabbitNode node;
+ OsgiJackrabbitRepositoryFactory repositoryFactory;
+ NodeSecurity nodeSecurity;
+ NodeHttp nodeHttp;
+ private KernelThread kernelThread;
void init() {
ClassLoader currentContextCl = Thread.currentThread()
ExtendedHttpService httpService = waitForHttpService();
nodeHttp = new NodeHttp(httpService, node, nodeSecurity);
+ // Kernel thread
+ kernelThread = new KernelThread(this);
+ kernelThread.setContextClassLoader(Kernel.class.getClassLoader());
+ kernelThread.start();
+
// Publish services to OSGi
nodeSecurity.publish();
node.publish(repositoryFactory);
void destroy() {
long begin = System.currentTimeMillis();
+ kernelThread.destroyAndJoin();
+
if (nodeHttp != null)
nodeHttp.destroy();
if (nodeSecurity != null)
--- /dev/null
+package org.argeo.cms.internal.kernel;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.api.stats.RepositoryStatistics;
+import org.apache.jackrabbit.stats.RepositoryStatisticsImpl;
+import org.argeo.cms.CmsException;
+
+/**
+ * Background thread started by the {@link Kernel}, which gather statistics and
+ * monitor/control other processes.
+ */
+class KernelThread extends Thread {
+ @SuppressWarnings("unused")
+ private final Kernel kernel;
+ private final RepositoryStatisticsImpl repoStats;
+
+ /** The smallest period of operation, in ms */
+ private final long PERIOD = 60 * 1000l;
+ /** One ms in ns */
+ private final static long m = 1000l * 1000l;
+ private final static long M = 1024l * 1024l;
+
+ private boolean running = true;
+
+ private Log kernelStatsLog = LogFactory.getLog("argeo.stats.kernel");
+ private Log nodeStatsLog = LogFactory.getLog("argeo.stats.node");
+
+ @SuppressWarnings("unused")
+ private long cycle = 0l;
+
+ public KernelThread(Kernel kernel) {
+ super(kernel.threadGroup, kernel.getClass().getSimpleName());
+ this.kernel = kernel;
+ this.repoStats = kernel.node.getRepositoryStatistics();
+ }
+
+ private void doSmallestPeriod() {
+ if (kernelStatsLog.isDebugEnabled()) {
+ StringBuilder line = new StringBuilder(64);
+ line.append("§\t");
+ long freeMem = Runtime.getRuntime().freeMemory() / M;
+ long totalMem = Runtime.getRuntime().totalMemory() / M;
+ long maxMem = Runtime.getRuntime().maxMemory() / M;
+ double loadAvg = ManagementFactory.getOperatingSystemMXBean()
+ .getSystemLoadAverage();
+ // in min
+ boolean min = true;
+ long uptime = ManagementFactory.getRuntimeMXBean().getUptime()
+ / (1000 * 60);
+ if (uptime > 24 * 60) {
+ min = false;
+ uptime = uptime / 60;
+ }
+ line.append(uptime).append(min ? " min" : " h").append('\t');
+ line.append(loadAvg).append('\t').append(maxMem).append('\t')
+ .append(totalMem).append('\t').append(freeMem).append('\t');
+ kernelStatsLog.debug(line);
+ }
+
+ if (nodeStatsLog.isDebugEnabled()) {
+ File dataDir = KernelUtils.getOsgiInstanceDir();
+ long freeSpace = dataDir.getUsableSpace() / M;
+ // File currentRoot = null;
+ // for (File root : File.listRoots()) {
+ // String rootPath = root.getAbsolutePath();
+ // if (dataDir.getAbsolutePath().startsWith(rootPath)) {
+ // if (currentRoot == null
+ // || (rootPath.length() > currentRoot.getPath()
+ // .length())) {
+ // currentRoot = root;
+ // }
+ // }
+ // }
+ // long totalSpace = currentRoot.getTotalSpace();
+ StringBuilder line = new StringBuilder(128);
+ line.append("§\t").append(freeSpace)
+ .append(" MB left in " + dataDir);
+ line.append('\n');
+ for (RepositoryStatistics.Type type : RepositoryStatistics.Type
+ .values()) {
+ long[] vals = repoStats.getTimeSeries(type).getValuePerMinute();
+ long val = vals[vals.length - 1];
+ line.append(type.name()).append('\t').append(val).append('\n');
+ }
+ nodeStatsLog.debug(line);
+ }
+ }
+
+ @Override
+ public void run() {
+ final long periodNs = PERIOD * m;
+ while (running) {
+ long beginNs = System.nanoTime();
+ doSmallestPeriod();
+
+ long waitNs = periodNs - (System.nanoTime() - beginNs);
+ if (waitNs < 0)
+ continue;
+ // wait
+ try {
+ sleep(waitNs / m, (int) (waitNs % m));
+ } catch (InterruptedException e) {
+ // silent
+ }
+ cycle++;
+ }
+ }
+
+ synchronized void destroyAndJoin() {
+ running = false;
+ notifyAll();
+ interrupt();
+ try {
+ join(PERIOD * 2);
+ } catch (InterruptedException e) {
+ throw new CmsException("Kernel thread destruction was interrupted");
+ }
+ }
+}