Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions core/src/org/labkey/core/CoreModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@
import org.labkey.core.qc.DataStateWriter;
import org.labkey.core.query.AttachmentAuditProvider;
import org.labkey.core.query.CoreQuerySchema;
import org.labkey.core.query.PostgresTableSizesTable;
import org.labkey.core.query.PostgresUserSchema;
import org.labkey.core.query.UserAuditProvider;
import org.labkey.core.query.UsersDomainKind;
Expand Down Expand Up @@ -1231,6 +1232,17 @@ public void moduleStartupComplete(ServletContext servletContext)
results.put("workbookCount", ContainerManager.getWorkbookCount());
results.put("archivedFolderCount", ContainerManager.getArchivedContainerCount());
results.put("databaseSize", CoreSchema.getInstance().getSchema().getScope().getDatabaseSize());

if (CoreSchema.getInstance().getSqlDialect().isPostgreSQL())
{
SQLFragment sql = new SQLFragment("SELECT table_schema, SUM(total_size) FROM ");
sql.append(new PostgresTableSizesTable(new PostgresUserSchema(User.getAdminServiceUser(), ContainerManager.getRoot())), "t");
sql.append(" GROUP BY table_schema");

var schemaSizes = new SqlSelector(CoreSchema.getInstance().getSchema(), sql).getValueMap();
results.put("databaseSchemaSize", schemaSizes);
}

results.put("scriptEngines", LabKeyScriptEngineManager.get().getScriptEngineMetrics());
results.put("customLabels", CustomLabelService.get().getCustomLabelMetrics());
Map<String, Long> roleAssignments = new HashMap<>();
Expand Down
10 changes: 10 additions & 0 deletions core/src/org/labkey/core/admin/AdminController.java
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ public static void registerAdminConsoleLinks()
{
AdminConsole.addLink(Diagnostics, "postgres activity", new ActionURL(PostgresStatActivityAction.class, root));
AdminConsole.addLink(Diagnostics, "postgres locks", new ActionURL(PostgresLocksAction.class, root));
AdminConsole.addLink(Diagnostics, "postgres table sizes", new ActionURL(PostgresTableSizesAction.class, root));
}

AdminConsole.addLink(Diagnostics, "profiler", new ActionURL(MiniProfilerController.ManageAction.class, root));
Expand Down Expand Up @@ -2666,6 +2667,15 @@ public PostgresLocksAction()
}
}

@AdminConsoleAction
public class PostgresTableSizesAction extends AbstractPostgresAction
{
public PostgresTableSizesAction()
{
super(PostgresUserSchema.POSTGRES_TABLE_SIZES_TABLE_NAME);
}
}

@AdminConsoleAction
public class DumpHeapAction extends SimpleViewAction<Object>
{
Expand Down
32 changes: 16 additions & 16 deletions core/src/org/labkey/core/query/PostgresLocksTable.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.labkey.core.query;

import org.jetbrains.annotations.NotNull;
import org.labkey.api.data.BaseColumnInfo;
import org.labkey.api.data.JdbcType;
import org.labkey.api.data.SQLFragment;
import org.labkey.api.query.ExprColumn;
import org.labkey.api.query.QueryForeignKey;

/** Backed by pg_locks view */
Expand All @@ -16,22 +16,22 @@ public PostgresLocksTable(@NotNull PostgresUserSchema userSchema)
setDescription("Shows info about the currently held Postgres locks");

// https://www.postgresql.org/docs/current/view-pg-locks.html
addColumn(new ExprColumn(this, "locktype", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".locktype"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "database", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".database"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "relation", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".relation"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "page", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".page"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "tuple", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".tuple"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "virtualxid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".virtualxid"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "transactionid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".transactionid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "classid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".classid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "objid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".objid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "objsubid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".objsubid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "virtualtransaction", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".virtualtransaction"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "pid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".pid"), JdbcType.INTEGER)).
addColumn(new BaseColumnInfo("locktype", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("database", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("relation", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("page", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("tuple", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("virtualxid", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("transactionid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("classid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("objid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("objsubid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("virtualtransaction", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("pid", this, JdbcType.INTEGER)).
setFk(new QueryForeignKey.Builder(userSchema, null).table(PostgresUserSchema.POSTGRES_STAT_ACTIVITY_TABLE_NAME).raw(true));
addColumn(new ExprColumn(this, "mode", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".mode"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "granted", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".granted"), JdbcType.BOOLEAN));
addColumn(new ExprColumn(this, "fastpath", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".fastpath"), JdbcType.BOOLEAN));
addColumn(new BaseColumnInfo("mode", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("granted", this, JdbcType.BOOLEAN));
addColumn(new BaseColumnInfo("fastpath", this, JdbcType.BOOLEAN));
}


Expand Down
47 changes: 24 additions & 23 deletions core/src/org/labkey/core/query/PostgresStatActivityTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.labkey.api.data.BaseColumnInfo;
import org.labkey.api.data.ColumnInfo;
import org.labkey.api.data.ConnectionWrapper;
import org.labkey.api.data.Container;
Expand Down Expand Up @@ -51,37 +52,37 @@ public PostgresStatActivityTable(@NotNull PostgresUserSchema userSchema)
setDescription("Shows info about the active Postgres connections and their activity");

// https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ACTIVITY-VIEW
addColumn(new ExprColumn(this, "datid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".datid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "datname", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".datname"), JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("datid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("datname", this, JdbcType.VARCHAR));

ExprColumn pidColumn = new ExprColumn(this, "pid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".pid"), JdbcType.INTEGER);
BaseColumnInfo pidColumn = new BaseColumnInfo("pid", this, JdbcType.INTEGER);
pidColumn.setKeyField(true);
addColumn(pidColumn);

addColumn(new ExprColumn(this, "leader_pid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".leader_pid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "usesysid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".usesysid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "usename", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".usename"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "application_name", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".application_name"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "client_addr", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".client_addr"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "client_hostname", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".client_hostname"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "client_port", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".client_port"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "backend_start", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".backend_start"), JdbcType.TIMESTAMP));
addColumn(new ExprColumn(this, "xact_start", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".xact_start"), JdbcType.TIMESTAMP));
addColumn(new ExprColumn(this, "query_start", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".query_start"), JdbcType.TIMESTAMP));
addColumn(new ExprColumn(this, "state_change", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".state_change"), JdbcType.TIMESTAMP));
addColumn(new ExprColumn(this, "wait_event_type", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".wait_event_type"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "wait_event", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".wait_event"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "state", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".state"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "backend_xid", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".backend_xid"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "backend_xmin", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".backend_xmin"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "query", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".query"), JdbcType.VARCHAR));
addColumn(new ExprColumn(this, "backend_type", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".backend_type"), JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("leader_pid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("usesysid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("usename", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("application_name", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("client_addr", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("client_hostname", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("client_port", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("backend_start", this, JdbcType.TIMESTAMP));
addColumn(new BaseColumnInfo("xact_start", this, JdbcType.TIMESTAMP));
addColumn(new BaseColumnInfo("query_start", this, JdbcType.TIMESTAMP));
addColumn(new BaseColumnInfo("state_change", this, JdbcType.TIMESTAMP));
addColumn(new BaseColumnInfo("wait_event_type", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("wait_event", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("state", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("backend_xid", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("backend_xmin", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("query", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("backend_type", this, JdbcType.VARCHAR));

// Our calculated values
var threadCol = addColumn(new ExprColumn(this, "threadsAndRequests", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".pid"), JdbcType.INTEGER));
threadCol.setDisplayColumnFactory(ThreadDisplayColumn::new);
addColumn(new ExprColumn(this, "running_time_ms", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".running_time_ms"), JdbcType.INTEGER));
addColumn(new ExprColumn(this, "blocked_by", new SQLFragment(ExprColumn.STR_TABLE_ALIAS + ".blocked_by"), JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("running_time_ms", this, JdbcType.INTEGER));
addColumn(new BaseColumnInfo("blocked_by", this, JdbcType.VARCHAR));

setDefaultVisibleColumns(Arrays.asList(
pidColumn.getFieldKey(),
Expand Down
39 changes: 39 additions & 0 deletions core/src/org/labkey/core/query/PostgresTableSizesTable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.labkey.core.query;

import org.jetbrains.annotations.NotNull;
import org.labkey.api.data.BaseColumnInfo;
import org.labkey.api.data.JdbcType;
import org.labkey.api.data.SQLFragment;

/** Backed by pg_locks view */
public class PostgresTableSizesTable extends AbstractPostgresAdminOnlyTable
{
public PostgresTableSizesTable(@NotNull PostgresUserSchema userSchema)
{
super(PostgresUserSchema.POSTGRES_TABLE_SIZES_TABLE_NAME, userSchema);

setDescription("Shows info Postgres table sizes");

addColumn(new BaseColumnInfo("table_schema", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("table_name", this, JdbcType.VARCHAR));
addColumn(new BaseColumnInfo("table_size", this, JdbcType.BIGINT)).setFormat("#,##0");
addColumn(new BaseColumnInfo("index_size", this, JdbcType.BIGINT)).setFormat("#,##0");
addColumn(new BaseColumnInfo("total_size", this, JdbcType.BIGINT)).setFormat("#,##0");
}

@Override
public @NotNull SQLFragment getFromSQL()
{
SQLFragment result = new SQLFragment();
result.append("""
SELECT
table_schema,
table_name,
pg_table_size(quote_ident(table_schema) || '.' || quote_ident(table_name)) AS table_size,
pg_indexes_size(quote_ident(table_schema) || '.' || quote_ident(table_name)) AS index_size,
pg_total_relation_size(quote_ident(table_schema) || '.' || quote_ident(table_name)) AS total_size
FROM information_schema.tables
WHERE table_schema NOT IN ('public', 'information_schema') AND table_schema NOT LIKE 'pg_%'""");
return result;
}
}
8 changes: 7 additions & 1 deletion core/src/org/labkey/core/query/PostgresUserSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class PostgresUserSchema extends UserSchema
{
public static final String POSTGRES_STAT_ACTIVITY_TABLE_NAME = "pg_stat_activity";
public static final String POSTGRES_LOCKS_TABLE_NAME = "pg_locks";
public static final String POSTGRES_TABLE_SIZES_TABLE_NAME = "pg_tablesizes";

public PostgresUserSchema(User user, Container container)
{
Expand All @@ -36,13 +37,18 @@ public boolean canReadSchema()
return new PostgresStatActivityTable(this);
if (POSTGRES_LOCKS_TABLE_NAME.equalsIgnoreCase(name))
return new PostgresLocksTable(this);
if (POSTGRES_TABLE_SIZES_TABLE_NAME.equalsIgnoreCase(name))
return new PostgresTableSizesTable(this);

return null;
}

@Override
public Set<String> getTableNames()
{
return Set.of(POSTGRES_STAT_ACTIVITY_TABLE_NAME, POSTGRES_LOCKS_TABLE_NAME);
return Set.of(
POSTGRES_LOCKS_TABLE_NAME,
POSTGRES_STAT_ACTIVITY_TABLE_NAME,
POSTGRES_TABLE_SIZES_TABLE_NAME);
}
}