提交 2839941e 编写于 作者: S serge-rider

#178 QM - history search

上级 8095e6c1
......@@ -16,8 +16,12 @@
*/
package org.jkiss.dbeaver.runtime.qm;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.qm.*;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
......@@ -104,9 +108,24 @@ public class QMControllerImpl implements QMController {
}
@Override
public List<QMMetaEvent> getPastMetaEvents()
public QMEventCursor getQueryHistoryCursor(
@NotNull DBRProgressMonitor monitor,
@Nullable String containerId,
@Nullable String sessionId,
@Nullable String searchString)
{
return metaHandler.getPastEvents();
if (CommonUtils.isEmpty(searchString)) {
return new QMUtils.ListCursorImpl(metaHandler.getPastEvents());
} else {
searchString = searchString.toLowerCase();
List<QMMetaEvent> filtered = new ArrayList<>();
for (QMMetaEvent event : metaHandler.getPastEvents()) {
if (event.getObject().getText().toLowerCase().contains(searchString)) {
filtered.add(event);
}
}
return new QMUtils.ListCursorImpl(filtered);
}
}
List<QMExecutionHandler> getHandlers()
......
......@@ -26,6 +26,7 @@ import org.jkiss.dbeaver.model.qm.QMEventFilter;
import org.jkiss.dbeaver.model.qm.QMMetaEvent;
import org.jkiss.dbeaver.model.qm.QMMetaListener;
import org.jkiss.dbeaver.model.qm.meta.*;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.utils.ContentUtils;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.dbeaver.utils.RuntimeUtils;
......@@ -85,7 +86,7 @@ public class QMLogFileWriter implements QMMetaListener, DBPPreferenceListener {
}
@Override
public synchronized void metaInfoChanged(@NotNull List<QMMetaEvent> events)
public synchronized void metaInfoChanged(DBRProgressMonitor monitor, @NotNull List<QMMetaEvent> events)
{
if (!enabled || logWriter == null) {
return;
......
......@@ -326,7 +326,7 @@ public class QMMCollectorImpl extends DefaultExecutionHandler implements QMMColl
// Dispatch all events
for (QMMetaListener listener : listeners) {
try {
listener.metaInfoChanged(events);
listener.metaInfoChanged(monitor, events);
} catch (Throwable e) {
log.error("Error notifying event listener", e);
}
......
......@@ -20,6 +20,7 @@ package org.jkiss.dbeaver.ui.controls.querylog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
......@@ -32,6 +33,7 @@ import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.*;
......@@ -45,6 +47,7 @@ import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPartSite;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.CoreCommands;
import org.jkiss.dbeaver.core.CoreMessages;
......@@ -57,6 +60,7 @@ import org.jkiss.dbeaver.model.preferences.DBPPreferenceListener;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.qm.*;
import org.jkiss.dbeaver.model.qm.meta.*;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.sql.SQLConstants;
import org.jkiss.dbeaver.model.sql.SQLDialect;
......@@ -67,13 +71,16 @@ import org.jkiss.dbeaver.ui.controls.TableColumnSortListener;
import org.jkiss.dbeaver.ui.dialogs.sql.BaseSQLDialog;
import org.jkiss.dbeaver.ui.editors.sql.handlers.OpenHandler;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.LongKeyMap;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
/**
......@@ -90,7 +97,6 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
public static final String COLOR_COMMITTED = "org.jkiss.dbeaver.txn.color.committed.background"; //= new RGB(0xBD, 0xFE, 0xBF);
public static final String COLOR_REVERTED = "org.jkiss.dbeaver.txn.color.reverted.background"; // = new RGB(0xFF, 0x63, 0x47);
public static final String COLOR_TRANSACTION = "org.jkiss.dbeaver.txn.color.transaction.background"; // = new RGB(0xFF, 0xE4, 0xB5);
private final Text searchText;
private static abstract class LogColumn {
private final String id;
......@@ -307,6 +313,7 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
};
private final IWorkbenchPartSite site;
private final Text searchText;
private Table logTable;
private java.util.List<ColumnDescriptor> columns = new ArrayList<>();
private LongKeyMap<TableItem> objectToItemMap = new LongKeyMap<>();
......@@ -326,11 +333,20 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
private int entriesPerPage = MIN_ENTRIES_PER_PAGE;
private Job filterJob;
public QueryLogViewer(Composite parent, IWorkbenchPartSite site, QMEventFilter filter, boolean showConnection)
{
super();
this.site = site;
this.filterJob = new AbstractJob("Filter query history") {
@Override
protected IStatus run(DBRProgressMonitor monitor) {
refresh();
return Status.OK_STATUS;
}
};
// Prepare colors
......@@ -356,7 +372,9 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
e.gc.setFont(null);
}
});
this.searchText.addModifyListener(e -> {
scheduleLogRefresh();
});
// Create log table
logTable = new Table(
......@@ -403,7 +421,7 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
this.filter = filter;
reloadEvents();
reloadEvents(null);
// Make sure app is initialized
DBeaverCore.getInstance();
......@@ -413,6 +431,15 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
DBeaverCore.getGlobalPreferenceStore().addPropertyChangeListener(this);
}
private synchronized void scheduleLogRefresh() {
// Many properties could be changed at once
// So here we just schedule single refresh job
if (logRefreshJob == null) {
logRefreshJob = new LogRefreshJob();
}
logRefreshJob.schedule(250);
}
public void setFilter(QMEventFilter filter) {
this.filter = filter;
}
......@@ -510,7 +537,7 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
@Override
public void refresh()
{
reloadEvents();
reloadEvents(searchText.getText());
}
private static String getObjectType(QMMObject object)
......@@ -593,7 +620,7 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
return null;
}
private void reloadEvents()
private void reloadEvents(@Nullable String searchString)
{
DBPPreferenceStore store = DBeaverCore.getGlobalPreferenceStore();
......@@ -601,11 +628,28 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
this.defaultFilter = new DefaultEventFilter();
clearLog();
updateMetaInfo(QMUtils.getPastMetaEvents());
// Extract events
final List<QMMetaEvent> events = new ArrayList<>();
RuntimeUtils.runTask(monitor -> {
try {
QMEventBrowser eventBrowser = QMUtils.getEventBrowser();
if (eventBrowser != null) {
String searchPattern = CommonUtils.isEmptyTrimmed(searchString) ? null : searchString.trim();
QMEventCursor cursor = eventBrowser.getQueryHistoryCursor(monitor, null, null, searchPattern);
while (events.size() < this.entriesPerPage && cursor.hasNextEvent(monitor)) {
events.add(cursor.nextEvent(monitor));
}
}
} catch (DBException e) {
throw new InvocationTargetException(e);
}
}, "Read meta events", 5000);
updateMetaInfo(events);
}
@Override
public void metaInfoChanged(@NotNull final java.util.List<QMMetaEvent> events) {
public void metaInfoChanged(DBRProgressMonitor monitor, @NotNull final List<QMMetaEvent> events) {
if (DBeaverCore.isClosing()) {
return;
}
......@@ -613,7 +657,7 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
DBeaverUI.asyncExec(() -> updateMetaInfo(events));
}
private synchronized void updateMetaInfo(final java.util.List<QMMetaEvent> events)
private synchronized void updateMetaInfo(final List<QMMetaEvent> events)
{
if (logTable.isDisposed()) {
return;
......@@ -911,37 +955,25 @@ public class QueryLogViewer extends Viewer implements QMMetaListener, DBPPrefere
return NLS.bind(CoreMessages.controls_querylog_format_minutes, String.valueOf(min), String.valueOf(sec));
}
private ConfigRefreshJob configRefreshJob = null;
private LogRefreshJob logRefreshJob = null;
@Override
public synchronized void preferenceChange(PreferenceChangeEvent event)
{
if (event.getProperty().startsWith(QMConstants.PROP_PREFIX)) {
// Many properties could be changed at once
// So here we just schedule single refresh job
if (configRefreshJob == null) {
configRefreshJob = new ConfigRefreshJob();
configRefreshJob.schedule(250);
configRefreshJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event)
{
configRefreshJob = null;
}
});
}
scheduleLogRefresh();
}
}
private class ConfigRefreshJob extends AbstractUIJob {
ConfigRefreshJob()
private class LogRefreshJob extends AbstractUIJob {
LogRefreshJob()
{
super(CoreMessages.controls_querylog_job_refresh);
}
@Override
protected IStatus runInUIThread(DBRProgressMonitor monitor)
{
reloadEvents();
refresh();
return Status.OK_STATUS;
}
}
......
......@@ -17,12 +17,10 @@
package org.jkiss.dbeaver.model.qm;
import java.util.List;
/**
* Query manager controller
*/
public interface QMController {
public interface QMController extends QMEventBrowser {
QMMCollector getMetaCollector();
......@@ -36,5 +34,4 @@ public interface QMController {
void unregisterMetaListener(QMMetaListener metaListener);
List<QMMetaEvent> getPastMetaEvents();
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed 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.jkiss.dbeaver.model.qm;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
/**
* Query manager history
*/
public interface QMEventBrowser {
QMEventCursor getQueryHistoryCursor(
@NotNull DBRProgressMonitor monitor,
@Nullable String containerId,
@Nullable String sessionId,
@Nullable String searchString);
}
......@@ -18,26 +18,25 @@
package org.jkiss.dbeaver.model.qm;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.exec.DBCExecutionPurpose;
import org.jkiss.dbeaver.model.qm.meta.QMMSessionInfo;
import org.jkiss.dbeaver.model.qm.meta.QMMStatementExecuteInfo;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import java.util.Date;
import java.util.List;
/**
* Query manager history
* Event cursor
*/
public interface QMEventHistory {
public interface QMEventCursor {
long getHistorySize();
long getTotalSize();
List<QMMStatementExecuteInfo> getQueryHistory(
@Nullable String containerId,
@Nullable String sessionId,
@Nullable DBCExecutionPurpose queryPurpose,
@Nullable Date startDate,
@Nullable Date endDate,
int maxQueries);
void scroll(long position, DBRProgressMonitor monitor) throws DBException;
boolean hasNextEvent(DBRProgressMonitor monitor) throws DBException;
QMMetaEvent nextEvent(DBRProgressMonitor monitor) throws DBException;
}
......@@ -18,6 +18,7 @@
package org.jkiss.dbeaver.model.qm;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import java.util.List;
......@@ -31,6 +32,6 @@ public interface QMMetaListener {
* Implementation must process all events in sync mode.
* QM collector will clean all closed objects after listeners notification.
*/
void metaInfoChanged(@NotNull List<QMMetaEvent> events);
void metaInfoChanged(@NotNull DBRProgressMonitor monitor, @NotNull List<QMMetaEvent> events);
}
......@@ -17,7 +17,9 @@
package org.jkiss.dbeaver.model.qm;
import org.eclipse.jgit.annotations.Nullable;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
import org.jkiss.dbeaver.model.exec.DBCExecutionPurpose;
......@@ -25,6 +27,7 @@ import org.jkiss.dbeaver.model.qm.meta.QMMSessionInfo;
import org.jkiss.dbeaver.model.qm.meta.QMMStatementExecuteInfo;
import org.jkiss.dbeaver.model.qm.meta.QMMTransactionInfo;
import org.jkiss.dbeaver.model.qm.meta.QMMTransactionSavepointInfo;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import java.util.Collections;
import java.util.List;
......@@ -34,48 +37,43 @@ import java.util.List;
*/
public class QMUtils {
public static final EmptyCursorImpl EMPTY_CURSOR = new EmptyCursorImpl();
private static DBPPlatform application;
private static QMExecutionHandler defaultHandler;
private static QMExecutionHandler defaultHandler;
public static void initApplication(DBPPlatform application) {
QMUtils.application = application;
}
public static QMExecutionHandler getDefaultHandler()
{
public static QMExecutionHandler getDefaultHandler() {
if (defaultHandler == null) {
defaultHandler = application.getQueryManager().getDefaultHandler();
}
return defaultHandler;
}
public static void registerHandler(QMExecutionHandler handler)
{
public static void registerHandler(QMExecutionHandler handler) {
application.getQueryManager().registerHandler(handler);
}
public static void unregisterHandler(QMExecutionHandler handler)
{
public static void unregisterHandler(QMExecutionHandler handler) {
application.getQueryManager().unregisterHandler(handler);
}
public static void registerMetaListener(QMMetaListener metaListener)
{
public static void registerMetaListener(QMMetaListener metaListener) {
application.getQueryManager().registerMetaListener(metaListener);
}
public static void unregisterMetaListener(QMMetaListener metaListener)
{
public static void unregisterMetaListener(QMMetaListener metaListener) {
application.getQueryManager().unregisterMetaListener(metaListener);
}
public static List<QMMetaEvent> getPastMetaEvents()
{
@Nullable
public static QMEventBrowser getEventBrowser() {
if (application == null) {
return Collections.emptyList();
return null;
}
QMController queryManager = application.getQueryManager();
return queryManager == null ? Collections.emptyList() : queryManager.getPastMetaEvents();
return application.getQueryManager();
}
public static boolean isTransactionActive(DBCExecutionContext executionContext) {
......@@ -150,4 +148,64 @@ public class QMUtils {
return new QMTransactionState(execCount, updateCount, txnMode, txnStartTime);
}
public static class ListCursorImpl implements QMEventCursor {
private final List<QMMetaEvent> events;
private int position;
public ListCursorImpl(List<QMMetaEvent> events) {
this.events = events;
this.position = 0;
}
@Override
public long getTotalSize() {
return events.size();
}
@Override
public void scroll(long position, DBRProgressMonitor monitor) throws DBException {
if (position < 0 || position >= events.size()) {
throw new DBException("Position is out of range (" + getTotalSize() + ")");
}
}
@Override
public boolean hasNextEvent(DBRProgressMonitor monitor) throws DBException {
return position < events.size();
}
@Override
public QMMetaEvent nextEvent(DBRProgressMonitor monitor) throws DBException {
QMMetaEvent event = events.get(position);
position++;
return event;
}
}
public static class EmptyCursorImpl implements QMEventCursor {
@Override
public long getTotalSize() {
return 0;
}
@Override
public void scroll(long position, DBRProgressMonitor monitor) throws DBException {
throw new DBException("Empty cursor");
}
@Override
public boolean hasNextEvent(DBRProgressMonitor monitor) throws DBException {
return false;
}
@Override
public QMMetaEvent nextEvent(DBRProgressMonitor monitor) throws DBException {
throw new DBException("Empty cursor");
}
}
}
......@@ -84,6 +84,8 @@ public abstract class QMMObject {
return closeTime > 0;
}
public abstract String getText();
protected synchronized void update()
{
this.updated = true;
......
......@@ -78,6 +78,11 @@ public class QMMSessionInfo extends QMMObject {
super.reopen();
}
@Override
public String getText() {
return contextName;
}
public QMMTransactionInfo changeTransactional(boolean transactional)
{
if (this.transactional == transactional) {
......
......@@ -150,4 +150,8 @@ public class QMMStatementExecuteInfo extends QMMObject {
return '"' + queryString + '"';
}
@Override
public String getText() {
return queryString;
}
}
......@@ -45,6 +45,11 @@ public class QMMStatementInfo extends QMMObject {
reference = null;
}
@Override
public String getText() {
return session.getText();
}
DBCStatement getReference()
{
return reference;
......
......@@ -96,4 +96,8 @@ public class QMMTransactionInfo extends QMMObject {
return "TRANSACTION";
}
@Override
public String getText() {
return session.getText();
}
}
......@@ -133,4 +133,9 @@ public class QMMTransactionSavepointInfo extends QMMObject {
}
return false;
}
@Override
public String getText() {
return transaction.getText();
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册