From f43e7520db24715459d2283fa51af80f0056094c Mon Sep 17 00:00:00 2001 From: Christian Hohnstaedt Date: Fri, 22 Mar 2019 12:43:04 +0100 Subject: [PATCH] Support concurrent database access. If a database is modified by another instance of XCA the passive instance reloads and displays the changed parts. --- lib/base.h | 2 +- lib/db_base.cpp | 24 +++++++++++++++++- lib/db_base.h | 4 ++- lib/db_crl.cpp | 1 + lib/db_x509.cpp | 7 ++++-- lib/db_x509.h | 1 + lib/db_x509req.cpp | 1 + lib/db_x509super.cpp | 1 + lib/pki_base.cpp | 2 +- lib/sql.cpp | 2 +- lib/sql.h | 1 + widgets/MW_database.cpp | 50 +++++++++++++++++++++++++++++-------- widgets/MainWindow.cpp | 9 +++---- widgets/MainWindow.h | 4 ++- widgets/Options.cpp | 1 - widgets/database_schema.cpp | 6 +++++ 16 files changed, 90 insertions(+), 26 deletions(-) diff --git a/lib/base.h b/lib/base.h index bdfcf6e4..ed6adb84 100644 --- a/lib/base.h +++ b/lib/base.h @@ -29,7 +29,7 @@ #endif #define C_FILE ((strrchr(__FILE__, '/') ? : __FILE__- 1) + 1) -#define TRACE qDebug("File: %s Func: %s Line: %d\n",C_FILE,__func__,__LINE__); +#define TRACE qDebug("File: %s Func: %s Line: %d", C_FILE, __func__, __LINE__); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #define nativeSeparator(s) QDir::toNativeSeparators(s) diff --git a/lib/db_base.cpp b/lib/db_base.cpp index 13c44c53..96dd662f 100644 --- a/lib/db_base.cpp +++ b/lib/db_base.cpp @@ -141,6 +141,27 @@ void db_base::loadContainer() emit columnsContentChanged(); } +void db_base::reloadContainer(const QList &typelist) +{ + bool match = false; + QList all_types = pkitype + pkitype_depends; + foreach(enum pki_type t, typelist) { + if (all_types.contains(t)) { + match = true; + break; + } + } + if (!match) + return; + qDebug() << "RELOAD" << class_name << all_types << typelist; + beginResetModel(); + delete rootItem; + rootItem = newPKI(); + endResetModel(); + + loadContainer(); +} + void db_base::updateHeaders() { QString s = allHeaders.toData(); @@ -288,6 +309,7 @@ void db_base::deletePKI(QModelIndex idx) TransDone(e); if (!e.isValid()) remFromCont(idx); + AffectedItems(pki->getSqlItemId()); mainwin->dbSqlError(e); } } catch (errorEx &err) { @@ -336,7 +358,7 @@ void db_base::inToCont(pki_base *pki) pki_base *db_base::getByName(QString desc) { QList list = sqlSELECTpki( - QString("SELECT id FROM items WHERE name=? AND ") + + QString("SELECT id FROM items WHERE name=? AND del=0 AND ") + sqlItemSelector(), QList() << QVariant(desc)); return list.isEmpty() ? NULL : list[0]; diff --git a/lib/db_base.h b/lib/db_base.h index ed80ae5a..8eedead9 100644 --- a/lib/db_base.h +++ b/lib/db_base.h @@ -44,6 +44,7 @@ class db_base: public QAbstractItemModel void _removePKI(pki_base *pki ); void removeItem(QString k); QList pkitype; + QList pkitype_depends; MainWindow *mainwin; QString class_name; /* Sql table containing the 'hash' of this items */ @@ -60,7 +61,7 @@ class db_base: public QAbstractItemModel bool isValidCol(int col) const; static XSqlQuery sqlSELECTpki(QString query, QList values = QList()); - void timerEvent(QTimerEvent * event); + void timerEvent(QTimerEvent *event); void restart_timer(); public: @@ -110,6 +111,7 @@ class db_base: public QAbstractItemModel pki_base *getByReference(pki_base *refpki); pki_base *getByPtr(void *); virtual void loadContainer(); + void reloadContainer(const QList &typelist); template QList getAll() { return sqlSELECTpki( diff --git a/lib/db_crl.cpp b/lib/db_crl.cpp index 3629c174..d4518326 100644 --- a/lib/db_crl.cpp +++ b/lib/db_crl.cpp @@ -23,6 +23,7 @@ db_crl::db_crl(MainWindow *mw) class_name = "crls"; sqlHashTable = "crls"; pkitype << revocation; + pkitype_depends << x509; updateHeaders(); loadContainer(); } diff --git a/lib/db_x509.cpp b/lib/db_x509.cpp index fc56ebaa..9fc7c094 100644 --- a/lib/db_x509.cpp +++ b/lib/db_x509.cpp @@ -31,13 +31,15 @@ db_x509::db_x509(MainWindow *mw) class_name = "certificates"; sqlHashTable = "certs"; pkitype << x509; + pkitype_depends << x509_req; updateHeaders(); loadContainer(); - dereferenceIssuer(); } -void db_x509::dereferenceIssuer() +void db_x509::loadContainer() { + db_x509super::loadContainer(); + XSqlQuery q("SELECT item, issuer FROM certs WHERE issuer is NOT NULL"); while (q.next()) { pki_base *root = rootItem; @@ -56,6 +58,7 @@ void db_x509::dereferenceIssuer() insertChild(root, cert); } } + emit columnsContentChanged(); } dbheaderList db_x509::getHeaders() diff --git a/lib/db_x509.h b/lib/db_x509.h index 33c26778..ff0e065c 100644 --- a/lib/db_x509.h +++ b/lib/db_x509.h @@ -34,6 +34,7 @@ class db_x509: public db_x509super db_x509(MainWindow *mw); pki_base *newPKI(enum pki_type type = none); pki_x509 *findIssuer(pki_x509 *client); + virtual void loadContainer(); bool updateView(); void updateViewAll(); diff --git a/lib/db_x509req.cpp b/lib/db_x509req.cpp index 84e6a6e4..5a7e69e1 100644 --- a/lib/db_x509req.cpp +++ b/lib/db_x509req.cpp @@ -20,6 +20,7 @@ db_x509req::db_x509req(MainWindow *mw) class_name = "requests"; sqlHashTable = "requests"; pkitype << x509_req; + pkitype_depends << x509; updateHeaders(); loadContainer(); } diff --git a/lib/db_x509super.cpp b/lib/db_x509super.cpp index 79d732dc..041ef23d 100644 --- a/lib/db_x509super.cpp +++ b/lib/db_x509super.cpp @@ -34,6 +34,7 @@ dbheaderList db_x509name::getHeaders() db_x509super::db_x509super(MainWindow *mw) :db_x509name(mw) { + pkitype_depends << asym_key << smartCard; } void db_x509super::loadContainer() diff --git a/lib/pki_base.cpp b/lib/pki_base.cpp index b83bb72f..910ab924 100644 --- a/lib/pki_base.cpp +++ b/lib/pki_base.cpp @@ -195,7 +195,7 @@ QSqlError pki_base::deleteSql() e = deleteSqlData(); if (e.isValid()) return e; - SQL_PREPARE(q, "DELETE FROM items WHERE id=?"); + SQL_PREPARE(q, "UPDATE items SET del=1 WHERE id=?"); q.bindValue(0, sqlItemId); q.exec(); return q.lastError(); diff --git a/lib/sql.cpp b/lib/sql.cpp index 09fe5a78..182ed89b 100644 --- a/lib/sql.cpp +++ b/lib/sql.cpp @@ -17,7 +17,7 @@ int DbTransaction::error; bool DbTransaction::hasTransaction; QList DbTransaction::items; -quint64 DatabaseStamp; +quint64 DbTransaction::DatabaseStamp; void DbTransaction::debug(const char *func, const char *file, int line) { diff --git a/lib/sql.h b/lib/sql.h index 3303ccf7..9c403bc4 100644 --- a/lib/sql.h +++ b/lib/sql.h @@ -34,6 +34,7 @@ class DbTransaction bool commit(const char *file, int line); bool rollback(const char *file, int line); bool done(QSqlError e, const char *file, int line); + static quint64 DatabaseStamp; static bool active() { return mutex > 0; diff --git a/widgets/MW_database.cpp b/widgets/MW_database.cpp index a32180f1..cc21684c 100644 --- a/widgets/MW_database.cpp +++ b/widgets/MW_database.cpp @@ -25,7 +25,7 @@ QSqlError MainWindow::initSqlDB() { - QStringList schemas[6]; + QStringList schemas[7]; #include "database_schema.cpp" @@ -274,6 +274,8 @@ int MainWindow::init_database(QString dbName) certs = new db_x509(this); temps = new db_temp(this); crls = new db_crl(this); + check_oom(keys && reqs && certs && temps && crls); + models << keys << reqs << certs << temps << crls; } catch (errorEx &err) { Error(err); @@ -325,9 +327,42 @@ int MainWindow::init_database(QString dbName) } dbindex->setText(tr("Database") + ": " + dbName); currentDB = dbName; + dbTimer = startTimer(1500); return ret; } +void MainWindow::timerEvent(QTimerEvent *event) +{ + quint64 stamp; + if (event->timerId() != dbTimer) + return; + XSqlQuery q; + SQL_PREPARE(q, "SELECT MAX(stamp) from items"); + q.exec(); + if (!q.first()) + return; + stamp = q.value(0).toULongLong(); + q.finish(); + qDebug() << "Stamp" << stamp + << "DatabaseStamp" << DbTransaction::DatabaseStamp; + + if (stamp > DbTransaction::DatabaseStamp) { + SQL_PREPARE(q, "SELECT DISTINCT type FROM items WHERE stamp=?"); + q.bindValue(0, stamp); + q.exec(); + + QList typelist; + while (q.next()) + typelist << (enum pki_type)q.value(0).toInt(); + + q.finish(); + qDebug() << "CHANGED" << typelist; + foreach(db_base *model, models) + model->reloadContainer(typelist); + } + DbTransaction::DatabaseStamp = stamp; +} + void MainWindow::dump_database() { QString dirname = QFileDialog::getExistingDirectory( @@ -464,6 +499,7 @@ void MainWindow::close_database() Settings.clear(); return; } + killTimer(dbTimer); qDebug("Closing database: %s", QString2filename(currentDB)); Settings["mw_geometry"] = QString("%1,%2,%3") .arg(size().width()) @@ -480,16 +516,8 @@ void MainWindow::close_database() tempView->setModel(); crlView->setModel(); - if (crls) - delete(crls); - if (reqs) - delete(reqs); - if (certs) - delete(certs); - if (temps) - delete(temps); - if (keys) - delete(keys); + qDeleteAll(models.begin(), models.end()); + models.clear(); db_base::flushLookup(); reqs = NULL; diff --git a/widgets/MainWindow.cpp b/widgets/MainWindow.cpp index 79a54cc8..ff9845fd 100644 --- a/widgets/MainWindow.cpp +++ b/widgets/MainWindow.cpp @@ -915,16 +915,13 @@ void MainWindow::generateDHparam() void MainWindow::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { - QList models; retranslateUi(this); dn_translations_setup(); init_menu(); update_history_menu(); - models << keys << reqs << certs << crls << temps; - foreach(db_base *model, models) { - if (model) - model->updateHeaders(); - } + foreach(db_base *model, models) + model->updateHeaders(); + if (!currentDB.isEmpty()) dbindex->setText(tr("Database") + ": " + currentDB); searchEdit->setPlaceholderText(tr("Search")); diff --git a/widgets/MainWindow.h b/widgets/MainWindow.h index a3ac4e87..231b3b06 100644 --- a/widgets/MainWindow.h +++ b/widgets/MainWindow.h @@ -76,7 +76,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void checkDB(); QSqlError initSqlDB(); QString openSqlDB(QString dbName); - QTimer *eachSecond; + QList models; protected: void init_images(); @@ -87,6 +87,8 @@ class MainWindow: public QMainWindow, public Ui::MainWindow QString homedir; int changeDB(QString fname); void keyPressEvent(QKeyEvent *e); + int dbTimer; + void timerEvent(QTimerEvent *event); public: static db_x509 *certs; diff --git a/widgets/Options.cpp b/widgets/Options.cpp index 1aea0a32..6409a686 100644 --- a/widgets/Options.cpp +++ b/widgets/Options.cpp @@ -210,7 +210,6 @@ void Options::on_searchPkcs11_clicked(void) void Options::Pkcs11ItemChanged(QListWidgetItem *item) { -TRACE pkcs11List->blockSignals(true); pkcs11_lib *l = pkcs11::get_libs().get_lib(item->text()); qDebug() << item->text() << item->checkState() << l->isEnabled() << l->isLoaded(); diff --git a/widgets/database_schema.cpp b/widgets/database_schema.cpp index e6cf9ea1..48b0be75 100644 --- a/widgets/database_schema.cpp +++ b/widgets/database_schema.cpp @@ -310,6 +310,12 @@ << "UPDATE settings SET value='6' WHERE key_='schema'" ; + schemas[6] +<< "ALTER TABLE items ADD del SMALLINT NOT NULL DEFAULT 0" +<< "CREATE INDEX i_items_del ON items (del)" +<< "UPDATE settings SET value='7' WHERE key_='schema'" + ; + /* When adding new tables or views, also add them to the list * in XSqlQuery::rewriteQuery(QString) in lib/sql.cpp */