diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java index 08cea43..e98cc8d 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java @@ -34,7 +34,7 @@ import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry; import org.apache.jackrabbit.core.security.JackrabbitSecurityManager; import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry; import org.apache.jackrabbit.core.state.ItemStateCacheFactory; -import org.apache.jackrabbit.core.stats.RepositoryStatisticsImpl; +import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; import org.apache.jackrabbit.core.stats.StatManager; import org.apache.jackrabbit.core.version.InternalVersionManagerImpl; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/QueryStatManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/QueryStatManager.java deleted file mode 100644 index 24abd2f..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/jmx/QueryStatManager.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.jmx; - -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - -import org.apache.jackrabbit.api.jmx.QueryStatManagerMBean; -import org.apache.jackrabbit.api.stats.QueryStat; -import org.apache.jackrabbit.api.stats.QueryStatDto; - -/** - * The QueryStatManagerMBean default implementation - * - */ -public class QueryStatManager implements QueryStatManagerMBean { - - private final QueryStat queryStat; - - public QueryStatManager(final QueryStat queryStat) { - this.queryStat = queryStat; - } - - public boolean isEnabled() { - return this.queryStat.isEnabled(); - } - - public void enable() { - this.queryStat.setEnabled(true); - } - - public void disable() { - this.queryStat.setEnabled(false); - } - - public void reset() { - this.queryStat.reset(); - } - - public int getSlowQueriesQueueSize() { - return queryStat.getSlowQueriesQueueSize(); - } - - public void setSlowQueriesQueueSize(int size) { - this.queryStat.setSlowQueriesQueueSize(size); - } - - public void clearSlowQueriesQueue() { - this.queryStat.clearSlowQueriesQueue(); - } - - public int getPopularQueriesQueueSize() { - return queryStat.getPopularQueriesQueueSize(); - } - - public void setPopularQueriesQueueSize(int size) { - queryStat.setPopularQueriesQueueSize(size); - } - - public void clearPopularQueriesQueue() { - queryStat.clearPopularQueriesQueue(); - } - - public TabularData getSlowQueries() { - return asTabularData(queryStat.getSlowQueries()); - } - - public TabularData getPopularQueries() { - return asTabularData(queryStat.getPopularQueries()); - } - - private TabularData asTabularData(QueryStatDto[] data) { - TabularDataSupport tds = null; - try { - CompositeType ct = QueryStatCompositeTypeFactory.getCompositeType(); - - TabularType tt = new TabularType(QueryStatDto.class.getName(), - "Query History", ct, QueryStatCompositeTypeFactory.index); - tds = new TabularDataSupport(tt); - - for (QueryStatDto q : data) { - tds.put(new CompositeDataSupport(ct, - QueryStatCompositeTypeFactory.names, - QueryStatCompositeTypeFactory.getValues(q))); - } - return tds; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - private static class QueryStatCompositeTypeFactory { - - private final static String[] index = { "position" }; - - private final static String[] names = { "position", "duration", - "occurrenceCount", "language", "statement", "creationTime" }; - - private final static String[] descriptions = { "position", "duration", - "occurrenceCount", "language", "statement", "creationTime" }; - - private final static OpenType[] types = { SimpleType.LONG, - SimpleType.LONG, SimpleType.INTEGER, SimpleType.STRING, - SimpleType.STRING, SimpleType.STRING }; - - public static CompositeType getCompositeType() throws OpenDataException { - return new CompositeType(QueryStat.class.getName(), - QueryStat.class.getName(), names, descriptions, types); - } - - public static Object[] getValues(QueryStatDto q) { - return new Object[] { q.getPosition(), q.getDuration(), - q.getOccurrenceCount(), q.getLanguage(), q.getStatement(), - q.getCreationTime() }; - } - } - -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java index d890eb1..272bae8 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java @@ -24,7 +24,7 @@ import org.apache.jackrabbit.core.data.DataStore; import org.apache.jackrabbit.core.fs.FileSystem; import org.apache.jackrabbit.core.id.NodeId; import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry; -import org.apache.jackrabbit.core.stats.RepositoryStatisticsImpl; +import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; /** * A PMContext is used to provide context information for a diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java index 8d7cb63..00c11e0 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java @@ -59,7 +59,7 @@ import org.apache.jackrabbit.core.state.NoSuchItemStateException; import org.apache.jackrabbit.core.state.NodeReferences; import org.apache.jackrabbit.core.state.NodeState; import org.apache.jackrabbit.core.state.PropertyState; -import org.apache.jackrabbit.core.stats.RepositoryStatisticsImpl; +import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; import org.apache.jackrabbit.core.util.StringIndex; import org.apache.jackrabbit.core.value.InternalValue; import org.apache.jackrabbit.spi.Name; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java index 13647aa..f65a8b4 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java @@ -36,7 +36,7 @@ import javax.jcr.version.VersionException; import org.apache.jackrabbit.api.stats.RepositoryStatistics.Type; import org.apache.jackrabbit.core.session.SessionContext; import org.apache.jackrabbit.core.session.SessionOperation; -import org.apache.jackrabbit.core.stats.RepositoryStatisticsImpl; +import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; import org.apache.jackrabbit.spi.Path; import org.apache.jackrabbit.spi.commons.conversion.NameException; import org.slf4j.Logger; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java index 33ec2fb..fa27dc7 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java @@ -37,7 +37,7 @@ import org.apache.jackrabbit.core.query.lucene.SearchIndex; import org.apache.jackrabbit.core.query.lucene.join.QueryEngine; import org.apache.jackrabbit.core.session.SessionContext; import org.apache.jackrabbit.core.session.SessionOperation; -import org.apache.jackrabbit.core.stats.RepositoryStatisticsImpl; +import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; import org.apache.jackrabbit.spi.commons.query.qom.BindVariableValueImpl; import org.apache.jackrabbit.spi.commons.query.qom.DefaultTraversingQOMTreeVisitor; import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java index bf0b655..d296368 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java @@ -27,7 +27,7 @@ import javax.jcr.Session; import org.apache.jackrabbit.core.WorkspaceManager; import org.apache.jackrabbit.core.observation.ObservationDispatcher; -import org.apache.jackrabbit.core.stats.RepositoryStatisticsImpl; +import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatCore.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatCore.java deleted file mode 100644 index 27be0f7..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatCore.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import org.apache.jackrabbit.api.stats.QueryStat; - -/** - * Extends external facing {@link QueryStat} with some internal operations - * - */ -public interface QueryStatCore extends QueryStat { - - /** - * Logs the call of each query ran on the repository. - * - * @param language - * the query language, see - * {@link org.apache.jackrabbit.spi.commons.name.NameConstants#JCR_LANGUAGE} - * @param statement - * the query - * @param durationMs - * time in ms - */ - void logQuery(final String language, final String statement, long durationMs); - -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoComparator.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoComparator.java deleted file mode 100644 index 31a4742..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoComparator.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.Comparator; - -import org.apache.jackrabbit.api.stats.QueryStatDto; - -/** - * QueryStatDto comparator by duration - * - */ -public class QueryStatDtoComparator implements Comparator { - public int compare(QueryStatDto o1, QueryStatDto o2) { - return new Long(o1.getDuration()).compareTo(o2.getDuration()); - } -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoImpl.java deleted file mode 100644 index 18699fe..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoImpl.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.Calendar; -import java.util.Date; - -import org.apache.jackrabbit.api.stats.QueryStatDto; - -/** - * Object that holds statistical info about a query. - * - */ -public class QueryStatDtoImpl implements QueryStatDto { - - private static final long serialVersionUID = 1L; - - /** - * lazy, computed at call time - */ - private long position; - - /** - * the time that the query was created - */ - private final Date creationTime; - - /** - * run duration in ms - */ - private final long durationMs; - - /** - * query language - */ - private final String language; - - /** - * query statement - */ - private final String statement; - - /** - * used in popular queries list - */ - private int occurrenceCount = 1; - - public QueryStatDtoImpl(final String language, final String statement, - long durationMs) { - this.durationMs = durationMs; - this.language = language; - this.statement = statement; - - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(System.currentTimeMillis() - durationMs); - this.creationTime = c.getTime(); - } - - public long getDuration() { - return durationMs; - } - - public String getLanguage() { - return language; - } - - public String getStatement() { - return statement; - } - - public String getCreationTime() { - return creationTime.toString(); - } - - public long getPosition() { - return position; - } - - public void setPosition(long position) { - this.position = position; - } - - @Override - public String toString() { - return "QueryStat [creationTime=" + creationTime + ", duration=" - + durationMs + ", position " + position + ", language=" - + language + ", statement=" + statement + "]"; - } - - public int getOccurrenceCount() { - return occurrenceCount; - } - - public void setOccurrenceCount(int occurrenceCount) { - this.occurrenceCount = occurrenceCount; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((language == null) ? 0 : language.hashCode()); - result = prime * result - + ((statement == null) ? 0 : statement.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - QueryStatDtoImpl other = (QueryStatDtoImpl) obj; - if (language == null) { - if (other.language != null) - return false; - } else if (!language.equals(other.language)) - return false; - if (statement == null) { - if (other.statement != null) - return false; - } else if (!statement.equals(other.statement)) - return false; - return true; - } - -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoOccurrenceComparator.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoOccurrenceComparator.java deleted file mode 100644 index 29c5be2..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatDtoOccurrenceComparator.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.Comparator; - -/** - * QueryStatDto comparator by occurrence count - * - * used by the popular queries queue - * - */ -public class QueryStatDtoOccurrenceComparator implements - Comparator { - public int compare(QueryStatDtoImpl o1, QueryStatDtoImpl o2) { - return new Integer(o1.getOccurrenceCount()).compareTo(o2 - .getOccurrenceCount()); - } -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatImpl.java deleted file mode 100644 index 3fd2c66..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/QueryStatImpl.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.concurrent.PriorityBlockingQueue; - -import org.apache.jackrabbit.api.stats.QueryStatDto; - -/** - * Default {@link QueryStatCore} implementation - * - */ -public class QueryStatImpl implements QueryStatCore { - - private final static Comparator comparator = new QueryStatDtoComparator(); - - private final BoundedPriorityBlockingQueue slowQueries = new BoundedPriorityBlockingQueue( - 15, comparator); - - private final static Comparator comparatorOccurrence = new QueryStatDtoOccurrenceComparator(); - - /** - * the real queue size will be bigger than the desired number of popular - * queries by POPULAR_QUEUE_MULTIPLIER times - */ - private static final int POPULAR_QUEUE_MULTIPLIER = 5; - - private final BoundedPriorityBlockingQueue popularQueries = new BoundedPriorityBlockingQueue( - 15 * POPULAR_QUEUE_MULTIPLIER, comparatorOccurrence); - - private static final class BoundedPriorityBlockingQueue extends - PriorityBlockingQueue { - - private static final long serialVersionUID = 1L; - private int maxSize; - - public BoundedPriorityBlockingQueue(int maxSize, - Comparator comparator) { - super(maxSize + 1, comparator); - this.maxSize = maxSize; - } - - @Override - public boolean offer(E e) { - boolean s = super.offer(e); - if (!s) { - return false; - } - if (size() > maxSize) { - poll(); - } - return true; - } - - public synchronized void setMaxSize(int maxSize) { - if (maxSize < this.maxSize) { - // shrink the queue - int delta = super.size() - maxSize; - for (int i = 0; i < delta; i++) { - E t = poll(); - if (t == null) { - break; - } - } - } - this.maxSize = maxSize; - } - - public int getMaxSize() { - return maxSize; - } - } - - private boolean enabled = false; - - public QueryStatImpl() { - } - - public int getSlowQueriesQueueSize() { - return slowQueries.getMaxSize(); - } - - public void setSlowQueriesQueueSize(int size) { - slowQueries.setMaxSize(size); - } - - public boolean isEnabled() { - return enabled; - } - - public synchronized void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public void logQuery(final String language, final String statement, - long durationMs) { - if (!enabled) { - return; - } - final QueryStatDtoImpl qs = new QueryStatDtoImpl(language, statement, - durationMs); - slowQueries.offer(qs); - - synchronized (popularQueries) { - Iterator iterator = popularQueries.iterator(); - while (iterator.hasNext()) { - QueryStatDtoImpl qsdi = iterator.next(); - if (qsdi.equals(qs)) { - qs.setOccurrenceCount(qsdi.getOccurrenceCount() + 1); - iterator.remove(); - break; - } - } - popularQueries.offer(qs); - } - } - - public void clearSlowQueriesQueue() { - slowQueries.clear(); - } - - public QueryStatDto[] getSlowQueries() { - QueryStatDto[] top = slowQueries.toArray(new QueryStatDto[slowQueries - .size()]); - Arrays.sort(top, Collections.reverseOrder(comparator)); - for (int i = 0; i < top.length; i++) { - top[i].setPosition(i + 1); - } - return top; - } - - public QueryStatDto[] getPopularQueries() { - QueryStatDtoImpl[] top; - int size = 0; - int maxSize = 0; - synchronized (popularQueries) { - top = popularQueries.toArray(new QueryStatDtoImpl[popularQueries - .size()]); - size = popularQueries.size(); - maxSize = popularQueries.getMaxSize(); - } - Arrays.sort(top, Collections.reverseOrder(comparatorOccurrence)); - int retSize = Math.min(size, maxSize / POPULAR_QUEUE_MULTIPLIER); - QueryStatDto[] retval = new QueryStatDto[retSize]; - for (int i = 0; i < retSize; i++) { - retval[i] = top[i]; - retval[i].setPosition(i + 1); - } - return retval; - } - - public int getPopularQueriesQueueSize() { - return popularQueries.getMaxSize() / POPULAR_QUEUE_MULTIPLIER; - } - - public void setPopularQueriesQueueSize(int size) { - popularQueries.setMaxSize(size * POPULAR_QUEUE_MULTIPLIER); - } - - public void clearPopularQueriesQueue() { - popularQueries.clear(); - } - - public void reset() { - clearSlowQueriesQueue(); - clearPopularQueriesQueue(); - } -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/RepositoryStatisticsImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/RepositoryStatisticsImpl.java deleted file mode 100644 index 9bae45f..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/RepositoryStatisticsImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.jackrabbit.api.stats.RepositoryStatistics; -import org.apache.jackrabbit.api.stats.TimeSeries; - -public class RepositoryStatisticsImpl implements - Iterable>, RepositoryStatistics { - - private final Map recorders = - new HashMap(); - - private final Map avg = - new HashMap(); - - public RepositoryStatisticsImpl() { - getOrCreateRecorder(Type.SESSION_COUNT); - getOrCreateRecorder(Type.SESSION_LOGIN_COUNTER); - - createAvg(Type.SESSION_READ_COUNTER, Type.SESSION_READ_DURATION, - Type.SESSION_READ_AVERAGE); - createAvg(Type.SESSION_WRITE_COUNTER, Type.SESSION_WRITE_DURATION, - Type.SESSION_WRITE_AVERAGE); - createAvg(Type.BUNDLE_CACHE_MISS_COUNTER, - Type.BUNDLE_CACHE_MISS_DURATION, Type.BUNDLE_CACHE_MISS_AVERAGE); - createAvg(Type.BUNDLE_WRITE_COUNTER, Type.BUNDLE_WRITE_DURATION, - Type.BUNDLE_WRITE_AVERAGE); - createAvg(Type.QUERY_COUNT, Type.QUERY_DURATION, Type.QUERY_AVERAGE); - - } - - private void createAvg(Type count, Type duration, Type avgTs) { - avg.put(avgTs.name(), new TimeSeriesAverage(getOrCreateRecorder(duration), - getOrCreateRecorder(count))); - } - - public RepositoryStatisticsImpl(ScheduledExecutorService executor) { - this(); - executor.scheduleAtFixedRate(new Runnable() { - public void run() { - recordOneSecond(); - } - }, 1, 1, TimeUnit.SECONDS); - } - - public synchronized Iterator> iterator() { - Map map = new TreeMap(); - map.putAll(recorders); - map.putAll(avg); - return map.entrySet().iterator(); - } - - public AtomicLong getCounter(Type type) { - return getOrCreateRecorder(type).getCounter(); - } - - public AtomicLong getCounter(String type, boolean resetValueEachSecond) { - return getOrCreateRecorder(type, resetValueEachSecond).getCounter(); - } - - public TimeSeries getTimeSeries(Type type) { - return getTimeSeries(type.name(), type.isResetValueEachSecond()); - } - - public TimeSeries getTimeSeries(String type, boolean resetValueEachSecond) { - if (avg.containsKey(type)) { - return avg.get(type); - } - return getOrCreateRecorder(type, resetValueEachSecond); - } - - private synchronized TimeSeriesRecorder getOrCreateRecorder(Type type) { - return getOrCreateRecorder(type.name(), type.isResetValueEachSecond()); - } - - private synchronized TimeSeriesRecorder getOrCreateRecorder(String type, boolean resetValueEachSecond) { - TimeSeriesRecorder recorder = recorders.get(type); - if (recorder == null) { - recorder = new TimeSeriesRecorder(resetValueEachSecond); - recorders.put(type, recorder); - } - return recorder; - } - - private synchronized void recordOneSecond() { - for (TimeSeriesRecorder recorder : recorders.values()) { - recorder.recordOneSecond(); - } - } -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/StatManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/StatManager.java index 8b888cc..d71c017 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/StatManager.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/StatManager.java @@ -18,6 +18,8 @@ package org.apache.jackrabbit.core.stats; import static java.lang.Boolean.getBoolean; +import org.apache.jackrabbit.stats.QueryStatCore; +import org.apache.jackrabbit.stats.QueryStatImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/TimeSeriesAverage.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/TimeSeriesAverage.java deleted file mode 100644 index e8f66db..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/TimeSeriesAverage.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import org.apache.jackrabbit.api.stats.TimeSeries; - -/** - * Time series of the average calculated by dividing a measured - * value by the counter of events during the measurement period. - */ -class TimeSeriesAverage implements TimeSeries { - - /** Value */ - private final TimeSeries value; - - /** Value */ - private final TimeSeries counter; - - public TimeSeriesAverage(TimeSeries value, TimeSeries counter) { - this.value = value; - this.counter = counter; - } - - //----------------------------------------------------------< TimeSeries > - - public long[] getValuePerSecond() { - long[] values = value.getValuePerSecond(); - long[] counts = counter.getValuePerSecond(); - return divide(values, counts); - } - - public long[] getValuePerMinute() { - long[] values = value.getValuePerMinute(); - long[] counts = counter.getValuePerMinute(); - return divide(values, counts); - } - - public synchronized long[] getValuePerHour() { - long[] values = value.getValuePerHour(); - long[] counts = counter.getValuePerHour(); - return divide(values, counts); - } - - public synchronized long[] getValuePerWeek() { - long[] values = value.getValuePerWeek(); - long[] counts = counter.getValuePerWeek(); - return divide(values, counts); - } - - //-------------------------------------------------------------< private > - - /** - * Per-entry division of two arrays. - * - * @param a array - * @param b array - * @return result of division - */ - private long[] divide(long[] a, long[] b) { - long[] c = new long[a.length]; - for (int i = 0; i < a.length; i++) { - if (b[i] != 0) { - c[i] = a[i] / b[i]; - } else { - c[i] = 0; - } - } - return c; - } - -} diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/TimeSeriesRecorder.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/TimeSeriesRecorder.java deleted file mode 100755 index 533615c..0000000 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/stats/TimeSeriesRecorder.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.jackrabbit.api.stats.TimeSeries; -import org.apache.jackrabbit.api.stats.RepositoryStatistics.Type; - -/** - * Recorder of a time series. An instance of this class records (and clears) - * the state of a given {@link AtomicLong} counter once every second and - * exposes the collected time series through the {@link TimeSeries} - * interface. - */ -class TimeSeriesRecorder implements TimeSeries { - - /** Value */ - private final AtomicLong counter = new AtomicLong(); - - /** Whether to reset value each second */ - private final boolean resetValueEachSecond; - - /** Measured value per second over the last minute. */ - private final long[] valuePerSecond = new long[60]; - - /** Measured value per minute over the last hour. */ - private final long[] valuePerMinute = new long[60]; - - /** Measured value per hour over the last week. */ - private final long[] valuePerHour = new long[7 * 24]; - - /** Measured value per week over the last three years. */ - private final long[] valuePerWeek = new long[3 * 52]; - - /** Current second (index in {@link #valuePerSecond}) */ - private int seconds = 0; - - /** Current minute (index in {@link #valuePerMinute}) */ - private int minutes = 0; - - /** Current hour (index in {@link #valuePerHour}) */ - private int hours = 0; - - /** Current week (index in {@link #valuePerWeek}) */ - private int weeks = 0; - - public TimeSeriesRecorder(Type type) { - this(type.isResetValueEachSecond()); - } - - public TimeSeriesRecorder(boolean resetValueEachSecond) { - this.resetValueEachSecond = resetValueEachSecond; - } - - /** - * Returns the {@link AtomicLong} instance used to measure the value for - * the time series. - * - * @return value - */ - public AtomicLong getCounter() { - return counter; - } - - /** - * Records the number of measured values over the past second and resets - * the counter. This method should be scheduled to be called once per - * second. - */ - public synchronized void recordOneSecond() { - if (resetValueEachSecond) { - valuePerSecond[seconds++] = counter.getAndSet(0); - } else { - valuePerSecond[seconds++] = counter.get(); - } - if (seconds == valuePerSecond.length) { - seconds = 0; - valuePerMinute[minutes++] = aggregate(valuePerSecond); - } - if (minutes == valuePerMinute.length) { - minutes = 0; - valuePerHour[hours++] = aggregate(valuePerMinute); - } - if (hours == valuePerHour.length) { - hours = 0; - valuePerWeek[weeks++] = aggregate(valuePerHour); - } - if (weeks == valuePerWeek.length) { - weeks = 0; - } - } - - //----------------------------------------------------------< TimeSeries > - - public synchronized long[] getValuePerSecond() { - return cyclicCopyFrom(valuePerSecond, seconds); - } - - public synchronized long[] getValuePerMinute() { - return cyclicCopyFrom(valuePerMinute, minutes); - } - - public synchronized long[] getValuePerHour() { - return cyclicCopyFrom(valuePerHour, hours); - } - - public synchronized long[] getValuePerWeek() { - return cyclicCopyFrom(valuePerWeek, weeks); - } - - //-------------------------------------------------------------< private > - - /** - * Returns the sum of all entries in the given array. - * - * @param array array to be summed - * @return sum of entries - */ - private long aggregate(long[] array) { - long sum = 0; - for (int i = 0; i < array.length; i++) { - - sum += array[i]; - } - if (resetValueEachSecond) { - return sum; - } - return sum / array.length; - } - - /** - * Returns a copy of the given cyclical array, with the element at - * the given position as the first element of the returned array. - * - * @param array cyclical array - * @param pos position of the first element - * @return copy of the array - */ - private static long[] cyclicCopyFrom(long[] array, int pos) { - long[] reverse = new long[array.length]; - for (int i = 0; i < array.length; i++) { - reverse[i] = array[(pos + i) % array.length]; - } - return reverse; - } -} diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/PersistenceManagerTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/PersistenceManagerTest.java index 0cedb02..d314f48 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/PersistenceManagerTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/PersistenceManagerTest.java @@ -18,8 +18,6 @@ package org.apache.jackrabbit.core.persistence; import java.io.File; import java.util.Arrays; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import javax.jcr.PropertyType; @@ -31,8 +29,6 @@ import org.apache.jackrabbit.core.RepositoryImpl; import org.apache.jackrabbit.core.fs.mem.MemoryFileSystem; import org.apache.jackrabbit.core.id.NodeId; import org.apache.jackrabbit.core.id.PropertyId; -import org.apache.jackrabbit.core.persistence.PMContext; -import org.apache.jackrabbit.core.persistence.PersistenceManager; import org.apache.jackrabbit.core.persistence.mem.InMemBundlePersistenceManager; import org.apache.jackrabbit.core.persistence.mem.InMemPersistenceManager; import org.apache.jackrabbit.core.persistence.obj.ObjectPersistenceManager; @@ -43,7 +39,7 @@ import org.apache.jackrabbit.core.state.NoSuchItemStateException; import org.apache.jackrabbit.core.state.NodeReferences; import org.apache.jackrabbit.core.state.NodeState; import org.apache.jackrabbit.core.state.PropertyState; -import org.apache.jackrabbit.core.stats.RepositoryStatisticsImpl; +import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; import org.apache.jackrabbit.core.util.db.ConnectionFactory; import org.apache.jackrabbit.core.value.InternalValue; import org.apache.jackrabbit.spi.Name; diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/QueryStatCoreTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/QueryStatCoreTest.java index 90bb3b3..5d14c15 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/QueryStatCoreTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/QueryStatCoreTest.java @@ -20,6 +20,8 @@ import static javax.jcr.query.Query.JCR_SQL2; import java.util.concurrent.atomic.AtomicLong; +import org.apache.jackrabbit.stats.QueryStatCore; +import org.apache.jackrabbit.stats.QueryStatImpl; import org.apache.jackrabbit.test.AbstractJCRTest; /** @@ -74,4 +76,4 @@ public class QueryStatCoreTest extends AbstractJCRTest { queryStat.setPopularQueriesQueueSize(newSize); assertEquals(newSize, queryStat.getPopularQueries().length); } -} \ No newline at end of file +} diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/RepositoryStatisticsImplTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/RepositoryStatisticsImplTest.java deleted file mode 100644 index ee80918..0000000 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/RepositoryStatisticsImplTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.Iterator; -import java.util.Map.Entry; - -import junit.framework.TestCase; - -import org.apache.jackrabbit.api.stats.TimeSeries; - -public class RepositoryStatisticsImplTest extends TestCase { - - private static final int DEFAULT_NUMBER_OF_ELEMENTS = 17; - - public void testDefaultIterator() { - RepositoryStatisticsImpl repositoryStatistics = new RepositoryStatisticsImpl(); - - Iterator> iterator = repositoryStatistics.iterator(); - int count = 0; - while (iterator.hasNext()) { - count++; - iterator.next(); - } - assertEquals(DEFAULT_NUMBER_OF_ELEMENTS, count); - } - - public void testIteratorWithSingleCustomType() { - RepositoryStatisticsImpl repositoryStatistics = new RepositoryStatisticsImpl(); - String type = "customType"; - repositoryStatistics.getCounter(type, false); - - Iterator> iterator = repositoryStatistics.iterator(); - int count = 0; - boolean customTypeExists = false; - while (iterator.hasNext()) { - count++; - Entry entry = iterator.next(); - if (type.equals(entry.getKey())) { - customTypeExists = true; - } - } - assertEquals(DEFAULT_NUMBER_OF_ELEMENTS + 1, count); - assertTrue(customTypeExists); - } -} diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/TestAll.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/TestAll.java index 5a4426e..426ee30 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/TestAll.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/TestAll.java @@ -35,8 +35,6 @@ public class TestAll extends TestCase { public static Test suite() { TestSuite suite = new TestSuite("Stats tests"); - suite.addTestSuite(RepositoryStatisticsImplTest.class); - suite.addTestSuite(TimeSeriesRecorderTest.class); suite.addTestSuite(QueryStatCoreTest.class); return suite; diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/TimeSeriesRecorderTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/TimeSeriesRecorderTest.java deleted file mode 100644 index 11cb4b6..0000000 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/stats/TimeSeriesRecorderTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.core.stats; - -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.jackrabbit.api.stats.RepositoryStatistics; - -import junit.framework.TestCase; - -public class TimeSeriesRecorderTest extends TestCase { - - public void testCounter() { - TimeSeriesRecorder recorder = new TimeSeriesRecorder( - RepositoryStatistics.Type.SESSION_READ_COUNTER); - AtomicLong counter = recorder.getCounter(); - - // initial values - assertValues(recorder.getValuePerSecond()); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // no changes in first second - recorder.recordOneSecond(); - assertValues(recorder.getValuePerSecond()); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // one increment in second - counter.incrementAndGet(); - recorder.recordOneSecond(); - assertValues(recorder.getValuePerSecond(), 1); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // two increments in second - counter.incrementAndGet(); - counter.incrementAndGet(); - recorder.recordOneSecond(); - assertValues(recorder.getValuePerSecond(), 2, 1); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // no changes in a second - recorder.recordOneSecond(); - assertValues(recorder.getValuePerSecond(), 0, 2, 1); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // ten increments in a second - counter.addAndGet(10); - recorder.recordOneSecond(); - assertValues(recorder.getValuePerSecond(), 10, 0, 2, 1); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // one minute - for (int i = 0; i < 60; i++) { - recorder.recordOneSecond(); - } - assertValues(recorder.getValuePerSecond()); - assertValues(recorder.getValuePerMinute(), 13); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // second minute - for (int i = 0; i < 60; i++) { - recorder.recordOneSecond(); - } - assertValues(recorder.getValuePerSecond()); - assertValues(recorder.getValuePerMinute(), 0, 13); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek()); - - // one hour - for (int i = 0; i < 60 * 60; i++) { - recorder.recordOneSecond(); - } - assertValues(recorder.getValuePerSecond()); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour(), 13); - assertValues(recorder.getValuePerWeek()); - - // one week - for (int i = 0; i < 7 * 24 * 60 * 60; i++) { - recorder.recordOneSecond(); - } - assertValues(recorder.getValuePerSecond()); - assertValues(recorder.getValuePerMinute()); - assertValues(recorder.getValuePerHour()); - assertValues(recorder.getValuePerWeek(), 13); - } - - private void assertValues(long[] values, long... expected) { - for (int i = 0; i < expected.length; i++) { - assertEquals(expected[i], values[values.length - i - 1]); - } - for (int i = expected.length; i < values.length; i++) { - assertEquals(0, values[values.length - i - 1]); - } - } - -} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatCore.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatCore.java new file mode 100644 index 0000000..7d12120 --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatCore.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import org.apache.jackrabbit.api.stats.QueryStat; + +/** + * Extends external facing {@link QueryStat} with some internal operations + * + */ +public interface QueryStatCore extends QueryStat { + + /** + * Logs the call of each query ran on the repository. + * + * @param language + * the query language, see + * {@link org.apache.jackrabbit.spi.commons.name.NameConstants#JCR_LANGUAGE} + * @param statement + * the query + * @param durationMs + * time in ms + */ + void logQuery(final String language, final String statement, long durationMs); + +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoComparator.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoComparator.java new file mode 100644 index 0000000..7a14e93 --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoComparator.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.Comparator; + +import org.apache.jackrabbit.api.stats.QueryStatDto; + +/** + * QueryStatDto comparator by duration + * + */ +public class QueryStatDtoComparator implements Comparator { + public int compare(QueryStatDto o1, QueryStatDto o2) { + return new Long(o1.getDuration()).compareTo(o2.getDuration()); + } +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoImpl.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoImpl.java new file mode 100644 index 0000000..06323aa --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoImpl.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.Calendar; +import java.util.Date; + +import org.apache.jackrabbit.api.stats.QueryStatDto; + +/** + * Object that holds statistical info about a query. + * + */ +public class QueryStatDtoImpl implements QueryStatDto { + + private static final long serialVersionUID = 1L; + + /** + * lazy, computed at call time + */ + private long position; + + /** + * the time that the query was created + */ + private final Date creationTime; + + /** + * run duration in ms + */ + private final long durationMs; + + /** + * query language + */ + private final String language; + + /** + * query statement + */ + private final String statement; + + /** + * used in popular queries list + */ + private int occurrenceCount = 1; + + public QueryStatDtoImpl(final String language, final String statement, + long durationMs) { + this.durationMs = durationMs; + this.language = language; + this.statement = statement; + + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(System.currentTimeMillis() - durationMs); + this.creationTime = c.getTime(); + } + + public long getDuration() { + return durationMs; + } + + public String getLanguage() { + return language; + } + + public String getStatement() { + return statement; + } + + public String getCreationTime() { + return creationTime.toString(); + } + + public long getPosition() { + return position; + } + + public void setPosition(long position) { + this.position = position; + } + + @Override + public String toString() { + return "QueryStat [creationTime=" + creationTime + ", duration=" + + durationMs + ", position " + position + ", language=" + + language + ", statement=" + statement + "]"; + } + + public int getOccurrenceCount() { + return occurrenceCount; + } + + public void setOccurrenceCount(int occurrenceCount) { + this.occurrenceCount = occurrenceCount; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((language == null) ? 0 : language.hashCode()); + result = prime * result + + ((statement == null) ? 0 : statement.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + QueryStatDtoImpl other = (QueryStatDtoImpl) obj; + if (language == null) { + if (other.language != null) + return false; + } else if (!language.equals(other.language)) + return false; + if (statement == null) { + if (other.statement != null) + return false; + } else if (!statement.equals(other.statement)) + return false; + return true; + } + +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoOccurrenceComparator.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoOccurrenceComparator.java new file mode 100644 index 0000000..dcaf5a6 --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatDtoOccurrenceComparator.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.Comparator; + +/** + * QueryStatDto comparator by occurrence count + * + * used by the popular queries queue + * + */ +public class QueryStatDtoOccurrenceComparator implements + Comparator { + public int compare(QueryStatDtoImpl o1, QueryStatDtoImpl o2) { + return new Integer(o1.getOccurrenceCount()).compareTo(o2 + .getOccurrenceCount()); + } +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatImpl.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatImpl.java new file mode 100644 index 0000000..fb23500 --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/QueryStatImpl.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.concurrent.PriorityBlockingQueue; + +import org.apache.jackrabbit.api.stats.QueryStatDto; + +/** + * Default {@link QueryStatCore} implementation + * + */ +public class QueryStatImpl implements QueryStatCore { + + private final static Comparator comparator = new QueryStatDtoComparator(); + + private final BoundedPriorityBlockingQueue slowQueries = new BoundedPriorityBlockingQueue( + 15, comparator); + + private final static Comparator comparatorOccurrence = new QueryStatDtoOccurrenceComparator(); + + /** + * the real queue size will be bigger than the desired number of popular + * queries by POPULAR_QUEUE_MULTIPLIER times + */ + private static final int POPULAR_QUEUE_MULTIPLIER = 5; + + private final BoundedPriorityBlockingQueue popularQueries = new BoundedPriorityBlockingQueue( + 15 * POPULAR_QUEUE_MULTIPLIER, comparatorOccurrence); + + private static final class BoundedPriorityBlockingQueue extends + PriorityBlockingQueue { + + private static final long serialVersionUID = 1L; + private int maxSize; + + public BoundedPriorityBlockingQueue(int maxSize, + Comparator comparator) { + super(maxSize + 1, comparator); + this.maxSize = maxSize; + } + + @Override + public boolean offer(E e) { + boolean s = super.offer(e); + if (!s) { + return false; + } + if (size() > maxSize) { + poll(); + } + return true; + } + + public synchronized void setMaxSize(int maxSize) { + if (maxSize < this.maxSize) { + // shrink the queue + int delta = super.size() - maxSize; + for (int i = 0; i < delta; i++) { + E t = poll(); + if (t == null) { + break; + } + } + } + this.maxSize = maxSize; + } + + public int getMaxSize() { + return maxSize; + } + } + + private boolean enabled = false; + + public QueryStatImpl() { + } + + public int getSlowQueriesQueueSize() { + return slowQueries.getMaxSize(); + } + + public void setSlowQueriesQueueSize(int size) { + slowQueries.setMaxSize(size); + } + + public boolean isEnabled() { + return enabled; + } + + public synchronized void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public void logQuery(final String language, final String statement, + long durationMs) { + if (!enabled) { + return; + } + final QueryStatDtoImpl qs = new QueryStatDtoImpl(language, statement, + durationMs); + slowQueries.offer(qs); + + synchronized (popularQueries) { + Iterator iterator = popularQueries.iterator(); + while (iterator.hasNext()) { + QueryStatDtoImpl qsdi = iterator.next(); + if (qsdi.equals(qs)) { + qs.setOccurrenceCount(qsdi.getOccurrenceCount() + 1); + iterator.remove(); + break; + } + } + popularQueries.offer(qs); + } + } + + public void clearSlowQueriesQueue() { + slowQueries.clear(); + } + + public QueryStatDto[] getSlowQueries() { + QueryStatDto[] top = slowQueries.toArray(new QueryStatDto[slowQueries + .size()]); + Arrays.sort(top, Collections.reverseOrder(comparator)); + for (int i = 0; i < top.length; i++) { + top[i].setPosition(i + 1); + } + return top; + } + + public QueryStatDto[] getPopularQueries() { + QueryStatDtoImpl[] top; + int size = 0; + int maxSize = 0; + synchronized (popularQueries) { + top = popularQueries.toArray(new QueryStatDtoImpl[popularQueries + .size()]); + size = popularQueries.size(); + maxSize = popularQueries.getMaxSize(); + } + Arrays.sort(top, Collections.reverseOrder(comparatorOccurrence)); + int retSize = Math.min(size, maxSize / POPULAR_QUEUE_MULTIPLIER); + QueryStatDto[] retval = new QueryStatDto[retSize]; + for (int i = 0; i < retSize; i++) { + retval[i] = top[i]; + retval[i].setPosition(i + 1); + } + return retval; + } + + public int getPopularQueriesQueueSize() { + return popularQueries.getMaxSize() / POPULAR_QUEUE_MULTIPLIER; + } + + public void setPopularQueriesQueueSize(int size) { + popularQueries.setMaxSize(size * POPULAR_QUEUE_MULTIPLIER); + } + + public void clearPopularQueriesQueue() { + popularQueries.clear(); + } + + public void reset() { + clearSlowQueriesQueue(); + clearPopularQueriesQueue(); + } +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/RepositoryStatisticsImpl.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/RepositoryStatisticsImpl.java new file mode 100644 index 0000000..974732d --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/RepositoryStatisticsImpl.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.jackrabbit.api.stats.RepositoryStatistics; +import org.apache.jackrabbit.api.stats.TimeSeries; + +public class RepositoryStatisticsImpl implements + Iterable>, RepositoryStatistics { + + private final Map recorders = + new HashMap(); + + private final Map avg = + new HashMap(); + + public RepositoryStatisticsImpl() { + getOrCreateRecorder(Type.SESSION_COUNT); + getOrCreateRecorder(Type.SESSION_LOGIN_COUNTER); + + createAvg(Type.SESSION_READ_COUNTER, Type.SESSION_READ_DURATION, + Type.SESSION_READ_AVERAGE); + createAvg(Type.SESSION_WRITE_COUNTER, Type.SESSION_WRITE_DURATION, + Type.SESSION_WRITE_AVERAGE); + createAvg(Type.BUNDLE_CACHE_MISS_COUNTER, + Type.BUNDLE_CACHE_MISS_DURATION, Type.BUNDLE_CACHE_MISS_AVERAGE); + createAvg(Type.BUNDLE_WRITE_COUNTER, Type.BUNDLE_WRITE_DURATION, + Type.BUNDLE_WRITE_AVERAGE); + createAvg(Type.QUERY_COUNT, Type.QUERY_DURATION, Type.QUERY_AVERAGE); + + } + + private void createAvg(Type count, Type duration, Type avgTs) { + avg.put(avgTs.name(), new TimeSeriesAverage(getOrCreateRecorder(duration), + getOrCreateRecorder(count))); + } + + public RepositoryStatisticsImpl(ScheduledExecutorService executor) { + this(); + executor.scheduleAtFixedRate(new Runnable() { + public void run() { + recordOneSecond(); + } + }, 1, 1, TimeUnit.SECONDS); + } + + public synchronized Iterator> iterator() { + Map map = new TreeMap(); + map.putAll(recorders); + map.putAll(avg); + return map.entrySet().iterator(); + } + + public AtomicLong getCounter(Type type) { + return getOrCreateRecorder(type).getCounter(); + } + + public AtomicLong getCounter(String type, boolean resetValueEachSecond) { + return getOrCreateRecorder(type, resetValueEachSecond).getCounter(); + } + + public TimeSeries getTimeSeries(Type type) { + return getTimeSeries(type.name(), type.isResetValueEachSecond()); + } + + public TimeSeries getTimeSeries(String type, boolean resetValueEachSecond) { + if (avg.containsKey(type)) { + return avg.get(type); + } + return getOrCreateRecorder(type, resetValueEachSecond); + } + + private synchronized TimeSeriesRecorder getOrCreateRecorder(Type type) { + return getOrCreateRecorder(type.name(), type.isResetValueEachSecond()); + } + + private synchronized TimeSeriesRecorder getOrCreateRecorder(String type, boolean resetValueEachSecond) { + TimeSeriesRecorder recorder = recorders.get(type); + if (recorder == null) { + recorder = new TimeSeriesRecorder(resetValueEachSecond); + recorders.put(type, recorder); + } + return recorder; + } + + private synchronized void recordOneSecond() { + for (TimeSeriesRecorder recorder : recorders.values()) { + recorder.recordOneSecond(); + } + } +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/TimeSeriesAverage.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/TimeSeriesAverage.java new file mode 100644 index 0000000..c7bf107 --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/TimeSeriesAverage.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import org.apache.jackrabbit.api.stats.TimeSeries; + +/** + * Time series of the average calculated by dividing a measured + * value by the counter of events during the measurement period. + */ +class TimeSeriesAverage implements TimeSeries { + + /** Value */ + private final TimeSeries value; + + /** Value */ + private final TimeSeries counter; + + public TimeSeriesAverage(TimeSeries value, TimeSeries counter) { + this.value = value; + this.counter = counter; + } + + //----------------------------------------------------------< TimeSeries > + + public long[] getValuePerSecond() { + long[] values = value.getValuePerSecond(); + long[] counts = counter.getValuePerSecond(); + return divide(values, counts); + } + + public long[] getValuePerMinute() { + long[] values = value.getValuePerMinute(); + long[] counts = counter.getValuePerMinute(); + return divide(values, counts); + } + + public synchronized long[] getValuePerHour() { + long[] values = value.getValuePerHour(); + long[] counts = counter.getValuePerHour(); + return divide(values, counts); + } + + public synchronized long[] getValuePerWeek() { + long[] values = value.getValuePerWeek(); + long[] counts = counter.getValuePerWeek(); + return divide(values, counts); + } + + //-------------------------------------------------------------< private > + + /** + * Per-entry division of two arrays. + * + * @param a array + * @param b array + * @return result of division + */ + private long[] divide(long[] a, long[] b) { + long[] c = new long[a.length]; + for (int i = 0; i < a.length; i++) { + if (b[i] != 0) { + c[i] = a[i] / b[i]; + } else { + c[i] = 0; + } + } + return c; + } + +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/TimeSeriesRecorder.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/TimeSeriesRecorder.java new file mode 100755 index 0000000..310c636 --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/TimeSeriesRecorder.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.jackrabbit.api.stats.TimeSeries; +import org.apache.jackrabbit.api.stats.RepositoryStatistics.Type; + +/** + * Recorder of a time series. An instance of this class records (and clears) + * the state of a given {@link AtomicLong} counter once every second and + * exposes the collected time series through the {@link TimeSeries} + * interface. + */ +public class TimeSeriesRecorder implements TimeSeries { + + /** Value */ + private final AtomicLong counter = new AtomicLong(); + + /** Whether to reset value each second */ + private final boolean resetValueEachSecond; + + /** Measured value per second over the last minute. */ + private final long[] valuePerSecond = new long[60]; + + /** Measured value per minute over the last hour. */ + private final long[] valuePerMinute = new long[60]; + + /** Measured value per hour over the last week. */ + private final long[] valuePerHour = new long[7 * 24]; + + /** Measured value per week over the last three years. */ + private final long[] valuePerWeek = new long[3 * 52]; + + /** Current second (index in {@link #valuePerSecond}) */ + private int seconds = 0; + + /** Current minute (index in {@link #valuePerMinute}) */ + private int minutes = 0; + + /** Current hour (index in {@link #valuePerHour}) */ + private int hours = 0; + + /** Current week (index in {@link #valuePerWeek}) */ + private int weeks = 0; + + public TimeSeriesRecorder(Type type) { + this(type.isResetValueEachSecond()); + } + + public TimeSeriesRecorder(boolean resetValueEachSecond) { + this.resetValueEachSecond = resetValueEachSecond; + } + + /** + * Returns the {@link AtomicLong} instance used to measure the value for + * the time series. + * + * @return value + */ + public AtomicLong getCounter() { + return counter; + } + + /** + * Records the number of measured values over the past second and resets + * the counter. This method should be scheduled to be called once per + * second. + */ + public synchronized void recordOneSecond() { + if (resetValueEachSecond) { + valuePerSecond[seconds++] = counter.getAndSet(0); + } else { + valuePerSecond[seconds++] = counter.get(); + } + if (seconds == valuePerSecond.length) { + seconds = 0; + valuePerMinute[minutes++] = aggregate(valuePerSecond); + } + if (minutes == valuePerMinute.length) { + minutes = 0; + valuePerHour[hours++] = aggregate(valuePerMinute); + } + if (hours == valuePerHour.length) { + hours = 0; + valuePerWeek[weeks++] = aggregate(valuePerHour); + } + if (weeks == valuePerWeek.length) { + weeks = 0; + } + } + + //----------------------------------------------------------< TimeSeries > + + public synchronized long[] getValuePerSecond() { + return cyclicCopyFrom(valuePerSecond, seconds); + } + + public synchronized long[] getValuePerMinute() { + return cyclicCopyFrom(valuePerMinute, minutes); + } + + public synchronized long[] getValuePerHour() { + return cyclicCopyFrom(valuePerHour, hours); + } + + public synchronized long[] getValuePerWeek() { + return cyclicCopyFrom(valuePerWeek, weeks); + } + + //-------------------------------------------------------------< private > + + /** + * Returns the sum of all entries in the given array. + * + * @param array array to be summed + * @return sum of entries + */ + private long aggregate(long[] array) { + long sum = 0; + for (int i = 0; i < array.length; i++) { + + sum += array[i]; + } + if (resetValueEachSecond) { + return sum; + } + return sum / array.length; + } + + /** + * Returns a copy of the given cyclical array, with the element at + * the given position as the first element of the returned array. + * + * @param array cyclical array + * @param pos position of the first element + * @return copy of the array + */ + private static long[] cyclicCopyFrom(long[] array, int pos) { + long[] reverse = new long[array.length]; + for (int i = 0; i < array.length; i++) { + reverse[i] = array[(pos + i) % array.length]; + } + return reverse; + } +} diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/jmx/QueryStatManager.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/jmx/QueryStatManager.java new file mode 100644 index 0000000..d1b7bf3 --- /dev/null +++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/stats/jmx/QueryStatManager.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats.jmx; + +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.apache.jackrabbit.api.jmx.QueryStatManagerMBean; +import org.apache.jackrabbit.api.stats.QueryStat; +import org.apache.jackrabbit.api.stats.QueryStatDto; + +/** + * The QueryStatManagerMBean default implementation + * + */ +public class QueryStatManager implements QueryStatManagerMBean { + + private final QueryStat queryStat; + + public QueryStatManager(final QueryStat queryStat) { + this.queryStat = queryStat; + } + + public boolean isEnabled() { + return this.queryStat.isEnabled(); + } + + public void enable() { + this.queryStat.setEnabled(true); + } + + public void disable() { + this.queryStat.setEnabled(false); + } + + public void reset() { + this.queryStat.reset(); + } + + public int getSlowQueriesQueueSize() { + return queryStat.getSlowQueriesQueueSize(); + } + + public void setSlowQueriesQueueSize(int size) { + this.queryStat.setSlowQueriesQueueSize(size); + } + + public void clearSlowQueriesQueue() { + this.queryStat.clearSlowQueriesQueue(); + } + + public int getPopularQueriesQueueSize() { + return queryStat.getPopularQueriesQueueSize(); + } + + public void setPopularQueriesQueueSize(int size) { + queryStat.setPopularQueriesQueueSize(size); + } + + public void clearPopularQueriesQueue() { + queryStat.clearPopularQueriesQueue(); + } + + public TabularData getSlowQueries() { + return asTabularData(queryStat.getSlowQueries()); + } + + public TabularData getPopularQueries() { + return asTabularData(queryStat.getPopularQueries()); + } + + private TabularData asTabularData(QueryStatDto[] data) { + TabularDataSupport tds = null; + try { + CompositeType ct = QueryStatCompositeTypeFactory.getCompositeType(); + + TabularType tt = new TabularType(QueryStatDto.class.getName(), + "Query History", ct, QueryStatCompositeTypeFactory.index); + tds = new TabularDataSupport(tt); + + for (QueryStatDto q : data) { + tds.put(new CompositeDataSupport(ct, + QueryStatCompositeTypeFactory.names, + QueryStatCompositeTypeFactory.getValues(q))); + } + return tds; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static class QueryStatCompositeTypeFactory { + + private final static String[] index = { "position" }; + + private final static String[] names = { "position", "duration", + "occurrenceCount", "language", "statement", "creationTime" }; + + private final static String[] descriptions = { "position", "duration", + "occurrenceCount", "language", "statement", "creationTime" }; + + private final static OpenType[] types = { SimpleType.LONG, + SimpleType.LONG, SimpleType.INTEGER, SimpleType.STRING, + SimpleType.STRING, SimpleType.STRING }; + + public static CompositeType getCompositeType() throws OpenDataException { + return new CompositeType(QueryStat.class.getName(), + QueryStat.class.getName(), names, descriptions, types); + } + + public static Object[] getValues(QueryStatDto q) { + return new Object[] { q.getPosition(), q.getDuration(), + q.getOccurrenceCount(), q.getLanguage(), q.getStatement(), + q.getCreationTime() }; + } + } + +} diff --git a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/stats/RepositoryStatisticsImplTest.java b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/stats/RepositoryStatisticsImplTest.java new file mode 100644 index 0000000..616396f --- /dev/null +++ b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/stats/RepositoryStatisticsImplTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.Iterator; +import java.util.Map.Entry; + +import junit.framework.TestCase; +import org.apache.jackrabbit.api.stats.TimeSeries; + +public class RepositoryStatisticsImplTest extends TestCase { + + private static final int DEFAULT_NUMBER_OF_ELEMENTS = 17; + + public void testDefaultIterator() { + RepositoryStatisticsImpl repositoryStatistics = new RepositoryStatisticsImpl(); + + Iterator> iterator = repositoryStatistics.iterator(); + int count = 0; + while (iterator.hasNext()) { + count++; + iterator.next(); + } + assertEquals(DEFAULT_NUMBER_OF_ELEMENTS, count); + } + + public void testIteratorWithSingleCustomType() { + RepositoryStatisticsImpl repositoryStatistics = new RepositoryStatisticsImpl(); + String type = "customType"; + repositoryStatistics.getCounter(type, false); + + Iterator> iterator = repositoryStatistics.iterator(); + int count = 0; + boolean customTypeExists = false; + while (iterator.hasNext()) { + count++; + Entry entry = iterator.next(); + if (type.equals(entry.getKey())) { + customTypeExists = true; + } + } + assertEquals(DEFAULT_NUMBER_OF_ELEMENTS + 1, count); + assertTrue(customTypeExists); + } +} diff --git a/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/stats/TimeSeriesRecorderTest.java b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/stats/TimeSeriesRecorderTest.java new file mode 100644 index 0000000..5bf4fb5 --- /dev/null +++ b/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/stats/TimeSeriesRecorderTest.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.stats; + +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.TestCase; +import org.apache.jackrabbit.api.stats.RepositoryStatistics; + +public class TimeSeriesRecorderTest extends TestCase { + + public void testCounter() { + TimeSeriesRecorder recorder = new TimeSeriesRecorder( + RepositoryStatistics.Type.SESSION_READ_COUNTER); + AtomicLong counter = recorder.getCounter(); + + // initial values + assertValues(recorder.getValuePerSecond()); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // no changes in first second + recorder.recordOneSecond(); + assertValues(recorder.getValuePerSecond()); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // one increment in second + counter.incrementAndGet(); + recorder.recordOneSecond(); + assertValues(recorder.getValuePerSecond(), 1); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // two increments in second + counter.incrementAndGet(); + counter.incrementAndGet(); + recorder.recordOneSecond(); + assertValues(recorder.getValuePerSecond(), 2, 1); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // no changes in a second + recorder.recordOneSecond(); + assertValues(recorder.getValuePerSecond(), 0, 2, 1); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // ten increments in a second + counter.addAndGet(10); + recorder.recordOneSecond(); + assertValues(recorder.getValuePerSecond(), 10, 0, 2, 1); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // one minute + for (int i = 0; i < 60; i++) { + recorder.recordOneSecond(); + } + assertValues(recorder.getValuePerSecond()); + assertValues(recorder.getValuePerMinute(), 13); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // second minute + for (int i = 0; i < 60; i++) { + recorder.recordOneSecond(); + } + assertValues(recorder.getValuePerSecond()); + assertValues(recorder.getValuePerMinute(), 0, 13); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek()); + + // one hour + for (int i = 0; i < 60 * 60; i++) { + recorder.recordOneSecond(); + } + assertValues(recorder.getValuePerSecond()); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour(), 13); + assertValues(recorder.getValuePerWeek()); + + // one week + for (int i = 0; i < 7 * 24 * 60 * 60; i++) { + recorder.recordOneSecond(); + } + assertValues(recorder.getValuePerSecond()); + assertValues(recorder.getValuePerMinute()); + assertValues(recorder.getValuePerHour()); + assertValues(recorder.getValuePerWeek(), 13); + } + + private void assertValues(long[] values, long... expected) { + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], values[values.length - i - 1]); + } + for (int i = expected.length; i < values.length; i++) { + assertEquals(0, values[values.length - i - 1]); + } + } + +}