Support concurrent database access.

If a database is modified by another instance of XCA the passive
instance reloads and displays the changed parts.
This commit is contained in:
Christian Hohnstaedt 2019-03-22 12:43:04 +01:00
parent ced0995862
commit f43e7520db
16 changed files with 90 additions and 26 deletions

View File

@ -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)

View File

@ -141,6 +141,27 @@ void db_base::loadContainer()
emit columnsContentChanged();
}
void db_base::reloadContainer(const QList<enum pki_type> &typelist)
{
bool match = false;
QList<enum pki_type> 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<pki_base*> list = sqlSELECTpki<pki_base>(
QString("SELECT id FROM items WHERE name=? AND ") +
QString("SELECT id FROM items WHERE name=? AND del=0 AND ") +
sqlItemSelector(),
QList<QVariant>() << QVariant(desc));
return list.isEmpty() ? NULL : list[0];

View File

@ -44,6 +44,7 @@ class db_base: public QAbstractItemModel
void _removePKI(pki_base *pki );
void removeItem(QString k);
QList<enum pki_type> pkitype;
QList<enum pki_type> 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<QVariant> values = QList<QVariant>());
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<enum pki_type> &typelist);
template <class T> QList<T *> getAll()
{
return sqlSELECTpki<T>(

View File

@ -23,6 +23,7 @@ db_crl::db_crl(MainWindow *mw)
class_name = "crls";
sqlHashTable = "crls";
pkitype << revocation;
pkitype_depends << x509;
updateHeaders();
loadContainer();
}

View File

@ -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()

View File

@ -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();

View File

@ -20,6 +20,7 @@ db_x509req::db_x509req(MainWindow *mw)
class_name = "requests";
sqlHashTable = "requests";
pkitype << x509_req;
pkitype_depends << x509;
updateHeaders();
loadContainer();
}

View File

@ -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()

View File

@ -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();

View File

@ -17,7 +17,7 @@ int DbTransaction::error;
bool DbTransaction::hasTransaction;
QList<quint64> DbTransaction::items;
quint64 DatabaseStamp;
quint64 DbTransaction::DatabaseStamp;
void DbTransaction::debug(const char *func, const char *file, int line)
{

View File

@ -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;

View File

@ -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<enum pki_type> 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;

View File

@ -915,16 +915,13 @@ void MainWindow::generateDHparam()
void MainWindow::changeEvent(QEvent *event)
{
if (event->type() == QEvent::LanguageChange) {
QList<db_base*> 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"));

View File

@ -76,7 +76,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow
void checkDB();
QSqlError initSqlDB();
QString openSqlDB(QString dbName);
QTimer *eachSecond;
QList<db_base*> 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;

View File

@ -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();

View File

@ -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
*/