lazy load the database sizes only when needed by the server inspector.

This commit is contained in:
eelke 2022-01-19 19:10:05 +01:00
parent 39195153cd
commit b5a706a2a2
10 changed files with 165 additions and 70 deletions

View file

@ -1,15 +1,19 @@
#include "DatabasesTableModel.h" #include "DatabasesTableModel.h"
#include "CustomDataRole.h" #include "CustomDataRole.h"
#include "OpenDatabase.h"
#include "ScopeGuard.h" #include "ScopeGuard.h"
#include "catalog/PgDatabaseCatalog.h" #include "catalog/PgDatabaseCatalog.h"
#include "catalog/PgDatabaseContainer.h" #include "catalog/PgDatabaseContainer.h"
#include "catalog/PgAuthIdContainer.h" #include "catalog/PgAuthIdContainer.h"
#include "ResultTableModelUtil.h" #include "ResultTableModelUtil.h"
#include <QtConcurrent>
#include "Pgsql_Connection.h"
using namespace Pgsql; using namespace Pgsql;
DatabasesTableModel::DatabasesTableModel(QObject *parent) DatabasesTableModel::DatabasesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent)
: BaseTableModel(parent) : BaseTableModel(parent)
, openDatabase(opendatabase)
{ {
} }
@ -18,15 +22,27 @@ void DatabasesTableModel::setDatabaseList(std::shared_ptr<const PgDatabaseCatalo
beginResetModel(); beginResetModel();
SCOPE_EXIT { endResetModel(); }; SCOPE_EXIT { endResetModel(); };
m_catalog = cat; databases.clear();
m_databases = cat->databases();
std::map<Oid, int> oidIndex;
m_catalog = cat;
auto dats = cat->databases();
databases.reserve(dats->count());
for (const auto& d : *dats)
{
databases.emplace_back(d);
oidIndex.emplace(d.oid(), databases.size() - 1);
}
StartLoadDatabaseSizes(std::move(oidIndex));
} }
QVariant DatabasesTableModel::headerData(int section, Qt::Orientation orientation, int role) const QVariant DatabasesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{ {
QVariant v; QVariant v;
if (orientation == Qt::Horizontal) { if (orientation == Qt::Horizontal)
if (role == Qt::DisplayRole) { {
if (role == Qt::DisplayRole)
{
switch (section) { switch (section) {
case NameCol: case NameCol:
v = tr("Name"); v = tr("Name");
@ -74,9 +90,7 @@ QVariant DatabasesTableModel::headerData(int section, Qt::Orientation orientatio
int DatabasesTableModel::rowCount(const QModelIndex &) const int DatabasesTableModel::rowCount(const QModelIndex &) const
{ {
int result = 0; int result = 0;
if (m_databases) { result = databases.size();
result = m_databases->count();
}
return result; return result;
} }
@ -90,7 +104,8 @@ int DatabasesTableModel::columnCount(const QModelIndex &) const
Oid DatabasesTableModel::getType(int column) const Oid DatabasesTableModel::getType(int column) const
{ {
Oid oid; Oid oid;
switch (column) { switch (column)
{
case AllowConnCol: case AllowConnCol:
case IsTemplateCol: case IsTemplateCol:
oid = Pgsql::bool_oid; oid = Pgsql::bool_oid;
@ -120,58 +135,113 @@ Oid DatabasesTableModel::getType(int column) const
QVariant DatabasesTableModel::getData(const QModelIndex &index) const QVariant DatabasesTableModel::getData(const QModelIndex &index) const
{ {
QVariant v; QVariant v;
//if (!index.isValid()) const Database &d = databases[index.row()];
if (m_databases) { const PgDatabase &db = d.database;
const PgDatabase &db = m_databases->getByIdx(index.row()); switch (index.column()) {
switch (index.column()) { case NameCol:
case NameCol: v = db.objectName();
v = db.objectName(); break;
break; case DbaCol:
case DbaCol: v = getRoleDisplayString(*m_catalog, db.dba);
v = getRoleDisplayString(*m_catalog, db.dba); break;
break; case EncodingCol:
case EncodingCol: // todo lookup encoding name
// todo lookup encoding name v = db.encodingString;
v = db.encodingString; break;
break; case CollateCol:
case CollateCol: v = db.collate;
v = db.collate; break;
break; case CTypeCol:
case CTypeCol: v = db.ctype;
v = db.ctype; break;
break; case IsTemplateCol:
case IsTemplateCol: v = db.isTemplate;
v = db.isTemplate; break;
break; case AllowConnCol:
case AllowConnCol: v = db.allowConn;
v = db.allowConn; break;
break; case ConnLimitCol:
case ConnLimitCol: v = db.connLimit;
v = db.connLimit; break;
break; case TablespaceCol:
case TablespaceCol: // todo lookup tablespace name
// todo lookup tablespace name v = getTablespaceDisplayString(*m_catalog, db.tablespace);
v = getTablespaceDisplayString(*m_catalog, db.tablespace); break;
break; case CommentCol:
case CommentCol: v = db.description;
v = db.description; break;
break; case SizeCol:
case SizeCol: if (d.size.totalBytes >= 0)
if (db.sizeBytes >= 0) v = d.size.totalBytes;
v = db.sizeBytes; break;
break; case AclCol:
case AclCol: v = db.aclString();
v = db.aclString(); break;
break; }
}
}
return v; return v;
} }
QVariant DatabasesTableModel::getDataMeaning(const QModelIndex &index) const QVariant DatabasesTableModel::getDataMeaning(const QModelIndex &index) const
{ {
if (index.column() == SizeCol) if (index.column() == SizeCol)
{
return static_cast<int>(DataMeaningBytes); return static_cast<int>(DataMeaningBytes);
}
return BaseTableModel::getDataMeaning(index); return BaseTableModel::getDataMeaning(index);
} }
void DatabasesTableModel::StartLoadDatabaseSizes(std::map<Oid, int> oidIndex)
{
QPointer p(this);
QtConcurrent::run([this]
{
return QueryDatabaseSizes();
})
.then(qApp, [p, oi = std::move(oidIndex)] (DatabaseSizes sizes)
{
if (p)
{
p.data()->PopulateSizes(std::move(oi), std::move(sizes));
}
});
}
DatabasesTableModel::DatabaseSizes DatabasesTableModel::QueryDatabaseSizes()
{
std::string q =
"SELECT pg_database.oid, "
" case when has_database_privilege(current_role, pg_database.oid, \n"
" 'connect') then pg_database_size(pg_database.oid) else -1 end \n"
"FROM pg_database";
Pgsql::Connection connection;
connection.connect(openDatabase->config().connectionString());
Pgsql::Result sizesResult = connection.query(q.c_str());
DatabaseSizes result;
result.reserve(sizesResult.rows());
for (auto& row : sizesResult)
{
DatabaseSize ds;
ds.oid = row.get(0);
ds.totalBytes = row.get(1);
result.push_back(ds);
}
return result;
}
void DatabasesTableModel::PopulateSizes(std::map<Oid, int> oidIndex, DatabaseSizes sizes)
{
for (auto & s : sizes)
{
auto findIter = oidIndex.find(s.oid);
if (findIter != oidIndex.end())
{
databases[findIter->second].size = s;
}
}
emit dataChanged(
createIndex(0, SizeCol),
createIndex(static_cast<int>(databases.size()), SizeCol)
);
}

View file

@ -2,11 +2,11 @@
#define DATABASESTABLEMODEL_H #define DATABASESTABLEMODEL_H
#include "BaseTableModel.h" #include "BaseTableModel.h"
#include "catalog/PgDatabase.h"
#include <memory> #include <memory>
class PgDatabaseContainer; class OpenDatabase;
class PgDatabaseCatalog; class PgDatabaseCatalog;
class PgDatabase;
/** Class for displaying the list of databases of a server in a QTableView /** Class for displaying the list of databases of a server in a QTableView
* *
@ -24,7 +24,7 @@ public:
explicit DatabasesTableModel(QObject *parent); explicit DatabasesTableModel(std::shared_ptr<OpenDatabase> opendatabase, QObject *parent);
void setDatabaseList(std::shared_ptr<const PgDatabaseCatalog> cat); void setDatabaseList(std::shared_ptr<const PgDatabaseCatalog> cat);
@ -41,8 +41,36 @@ public:
protected: protected:
virtual QVariant getDataMeaning(const QModelIndex &index) const override; virtual QVariant getDataMeaning(const QModelIndex &index) const override;
private: private:
class DatabaseSize {
public:
Oid oid;
int64_t totalBytes;
DatabaseSize()
: oid(InvalidOid)
, totalBytes(-1)
{}
};
using DatabaseSizes = std::vector<DatabaseSize>;
class Database {
public:
PgDatabase database;
DatabaseSize size;
Database(const PgDatabase &db)
: database(db)
{}
};
using Databases = std::vector<Database>;
std::shared_ptr<OpenDatabase> openDatabase;
std::shared_ptr<const PgDatabaseCatalog> m_catalog; std::shared_ptr<const PgDatabaseCatalog> m_catalog;
std::shared_ptr<const PgDatabaseContainer> m_databases; Databases databases;
void StartLoadDatabaseSizes(std::map<Oid, int> oidIndex);
DatabaseSizes QueryDatabaseSizes();
void PopulateSizes(std::map<Oid, int> oidIndex, DatabaseSizes sizes);
}; };
#endif // DATABASESTABLEMODEL_H #endif // DATABASESTABLEMODEL_H

View file

@ -188,7 +188,7 @@ void TablesTableModel::StartLoadTableSizes(std::map<Oid, int> oidIndex)
{ {
return QueryTableSizes(); return QueryTableSizes();
}) })
.then(qApp, [p, oidIndex] (std::vector<TableSize> sizes) .then(qApp, [p, oidIndex] (TableSizes sizes)
{ {
if (p) if (p)
{ {

View file

@ -60,12 +60,12 @@ private:
: oid(0) : oid(0)
{} {}
}; };
using TableSizes = std::vector<class TableSize>; using TableSizes = std::vector<TableSize>;
class Table { class Table {
public: public:
PgClass _class; PgClass _class;
class TableSize sizes; TableSize sizes;
Table(const PgClass &cls) Table(const PgClass &cls)
: _class(cls) : _class(cls)

View file

@ -5,9 +5,9 @@
#include "PgLabTableView.h" #include "PgLabTableView.h"
DatabasesPage::DatabasesPage(QWidget * parent) DatabasesPage::DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget * parent)
: QSplitter(Qt::Horizontal, parent) : QSplitter(Qt::Horizontal, parent)
, m_databasesTableView(this) , m_databasesTableView(this, new DatabasesTableModel(opendatabase, this))
{ {
auto tv = m_databasesTableView.tableView(); auto tv = m_databasesTableView.tableView();
tv->setSelectionMode(QAbstractItemView::SingleSelection); tv->setSelectionMode(QAbstractItemView::SingleSelection);

View file

@ -12,7 +12,7 @@ class QSortFilterProxyModel;
class DatabasesPage: public QSplitter { class DatabasesPage: public QSplitter {
public: public:
explicit DatabasesPage(QWidget * parent = nullptr); explicit DatabasesPage(std::shared_ptr<OpenDatabase> opendatabase, QWidget * parent = nullptr);
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat); void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat);

View file

@ -9,7 +9,7 @@
ServerInspector::ServerInspector(std::shared_ptr<OpenDatabase> open_database, QWidget *parent) ServerInspector::ServerInspector(std::shared_ptr<OpenDatabase> open_database, QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
m_databasesPage = new DatabasesPage(this); m_databasesPage = new DatabasesPage(open_database, this);
m_rolesPage = new RolesPage(this); m_rolesPage = new RolesPage(this);
m_tabWidget = new QTabWidget(this); m_tabWidget = new QTabWidget(this);

View file

@ -17,7 +17,6 @@ public:
bool allowConn; bool allowConn;
int connLimit; int connLimit;
Oid tablespace; Oid tablespace;
int64_t sizeBytes;
QString description; QString description;
using PgServerObject::PgServerObject; using PgServerObject::PgServerObject;

View file

@ -6,7 +6,6 @@ std::string PgDatabaseContainer::getLoadQuery() const
return return
"SELECT pg_database.oid, datname, datdba, encoding, pg_encoding_to_char(encoding), datcollate,\n" "SELECT pg_database.oid, datname, datdba, encoding, pg_encoding_to_char(encoding), datcollate,\n"
" datctype, datistemplate, datallowconn, datconnlimit, dattablespace, \n" " datctype, datistemplate, datallowconn, datconnlimit, dattablespace, \n"
" case when has_database_privilege(current_role, pg_database.oid, 'connect') then pg_database_size(pg_database.oid) else -1 end,\n"
" d.description, datacl\n" " d.description, datacl\n"
"FROM pg_database\n" "FROM pg_database\n"
" LEFT JOIN pg_catalog.pg_shdescription AS d ON (objoid=pg_database.oid)"; " LEFT JOIN pg_catalog.pg_shdescription AS d ON (objoid=pg_database.oid)";
@ -20,7 +19,7 @@ PgDatabase PgDatabaseContainer::loadElem(const Pgsql::Row &row)
QString name = col.nextValue(); QString name = col.nextValue();
PgDatabase v(m_catalog, oid, name); PgDatabase v(m_catalog, oid, name);
col >> v.dba >> v.encoding >> v.encodingString >> v.collate >> v.ctype >> v.isTemplate col >> v.dba >> v.encoding >> v.encodingString >> v.collate >> v.ctype >> v.isTemplate
>> v.allowConn >> v.connLimit >> v.tablespace >> v.sizeBytes >> v.description; >> v.allowConn >> v.connLimit >> v.tablespace >> v.description;
AclList acl_list; AclList acl_list;
col >> acl_list; col >> acl_list;

View file

@ -13,7 +13,6 @@ namespace Pgsql {
class PgDatabaseContainer: public PgContainer<PgDatabase> { class PgDatabaseContainer: public PgContainer<PgDatabase> {
public: public:
//explicit PgDatabaseContainer(PgDatabaseCatalog *cat);
using PgContainer<PgDatabase>::PgContainer; using PgContainer<PgDatabase>::PgContainer;
virtual std::string getLoadQuery() const override; virtual std::string getLoadQuery() const override;