Skip to content

Commit a0f7e10

Browse files
committed
#2074 note-relations: allow multithreaded note subfolder fetch
Signed-off-by: Patrizio Bekerle <[email protected]>
1 parent b7631c1 commit a0f7e10

8 files changed

+121
-45
lines changed

src/entities/note.cpp

+13-11
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ bool Note::isShared() const { return this->_shareId > 0; }
8282

8383
QString Note::getFileName() const { return this->_fileName; }
8484

85-
NoteSubFolder Note::getNoteSubFolder() const {
86-
return NoteSubFolder::fetch(this->_noteSubFolderId);
85+
NoteSubFolder Note::getNoteSubFolder(const QString &connectionName) const {
86+
return NoteSubFolder::fetch(this->_noteSubFolderId, connectionName);
8787
}
8888

8989
int Note::getNoteSubFolderId() const { return this->_noteSubFolderId; }
@@ -1760,12 +1760,12 @@ QString Note::getFullFilePathForFile(const QString &fileName) {
17601760
return canonicalFilePath;
17611761
}
17621762

1763-
QString Note::getFilePathRelativeToNote(const Note &note) const {
1764-
const QDir dir(fullNoteFilePath());
1763+
QString Note::getFilePathRelativeToNote(const Note &note, const QString &connectionName) const {
1764+
const QDir dir(fullNoteFilePath(connectionName));
17651765

17661766
// for some reason there is a leading "../" too much
17671767
static const QRegularExpression re(QStringLiteral(R"(^\.\.\/)"));
1768-
QString path = dir.relativeFilePath(note.fullNoteFilePath()).remove(re);
1768+
QString path = dir.relativeFilePath(note.fullNoteFilePath(connectionName)).remove(re);
17691769

17701770
// if "note" is the current note we want to use the real filename
17711771
if (path == QChar('.')) {
@@ -1831,7 +1831,9 @@ QString Note::urlDecodeNoteUrl(QString url) {
18311831
/**
18321832
* Returns the full path of the note file
18331833
*/
1834-
QString Note::fullNoteFilePath() const { return getFullFilePathForFile(relativeNoteFilePath()); }
1834+
QString Note::fullNoteFilePath(const QString &connectionName) const {
1835+
return getFullFilePathForFile(relativeNoteFilePath(QString(), connectionName));
1836+
}
18351837

18361838
/**
18371839
* Returns the full path of directory of the note file
@@ -1845,17 +1847,17 @@ QString Note::fullNoteFileDirPath() const {
18451847
/**
18461848
* Returns the relative path of the note file
18471849
*/
1848-
QString Note::relativeNoteFilePath(QString separator) const {
1850+
QString Note::relativeNoteFilePath(QString separator, const QString &connectionName) const {
18491851
QString fullFileName = _fileName;
18501852

18511853
if (separator.isEmpty()) {
18521854
separator = Utils::Misc::dirSeparator();
18531855
}
18541856

18551857
if (_noteSubFolderId > 0) {
1856-
const NoteSubFolder noteSubFolder = getNoteSubFolder();
1858+
const NoteSubFolder noteSubFolder = getNoteSubFolder(connectionName);
18571859
if (noteSubFolder.isFetched()) {
1858-
fullFileName.prepend(noteSubFolder.relativePath() + separator);
1860+
fullFileName.prepend(noteSubFolder.relativePath('/', connectionName) + separator);
18591861
}
18601862
}
18611863

@@ -3216,7 +3218,7 @@ void Note::addTextToLinkedNoteHashIfFound(const Note &note, const QString &noteT
32163218
*
32173219
* @return Hash of notes and the link hits
32183220
*/
3219-
QHash<Note, QSet<LinkHit>> Note::findLinkedNotes(QVector<Note> noteList) {
3221+
QHash<Note, QSet<LinkHit>> Note::findLinkedNotes(QVector<Note> noteList, const QString &connectionName) {
32203222
const auto noteText = getNoteText();
32213223
_linkedNoteHash.clear();
32223224

@@ -3227,7 +3229,7 @@ QHash<Note, QSet<LinkHit>> Note::findLinkedNotes(QVector<Note> noteList) {
32273229
// Check all notes and look if the current note contains a link to those notes
32283230
// We don't need to care about legacy links, because they don't know subfolders
32293231
for (const Note &note : noteList) {
3230-
const QString &relativePathToNote = getFilePathRelativeToNote(note);
3232+
const QString &relativePathToNote = getFilePathRelativeToNote(note, connectionName);
32313233

32323234
// We now don't escape slashes in the relative file path, but previously we did,
32333235
// so we need to search for both

src/entities/note.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class Note {
117117

118118
static QString getFullFilePathForFile(const QString &fileName);
119119

120-
QString getFilePathRelativeToNote(const Note &note) const;
120+
QString getFilePathRelativeToNote(const Note &note, const QString &connectionName = QStringLiteral("memory")) const;
121121

122122
static int storeDirtyNotesToDisk(Note &currentNote, bool *currentNoteChanged = nullptr,
123123
bool *noteWasRenamed = nullptr,
@@ -182,7 +182,7 @@ class Note {
182182

183183
QUrl fullNoteFileUrl() const;
184184

185-
QString fullNoteFilePath() const;
185+
QString fullNoteFilePath(const QString &connectionName = QStringLiteral("memory")) const;
186186

187187
QString fullNoteFileDirPath() const;
188188

@@ -221,7 +221,7 @@ class Note {
221221

222222
QString fileBaseName(bool withFullName = false);
223223

224-
NoteSubFolder getNoteSubFolder() const;
224+
NoteSubFolder getNoteSubFolder(const QString &connectionName = QStringLiteral("memory")) const;
225225

226226
void setNoteSubFolder(const NoteSubFolder &noteSubFolder);
227227

@@ -239,7 +239,7 @@ class Note {
239239

240240
bool isInCurrentNoteSubFolder() const;
241241

242-
QString relativeNoteFilePath(QString separator = QString()) const;
242+
QString relativeNoteFilePath(QString separator = QString(), const QString &connectionName = QStringLiteral("memory")) const;
243243

244244
QString relativeNoteSubFolderPath() const;
245245

@@ -383,7 +383,7 @@ class Note {
383383

384384
QSet<Note> findBacklinks() const;
385385

386-
QHash<Note, QSet<LinkHit>> findLinkedNotes(QVector<Note> noteList = QVector<Note>());
386+
QHash<Note, QSet<LinkHit>> findLinkedNotes(QVector<Note> noteList = QVector<Note>(), const QString &connectionName = QStringLiteral("memory"));
387387

388388
QHash<Note, QSet<LinkHit>> findReverseLinkNotes();
389389

src/entities/notesubfolder.cpp

+56-14
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ int NoteSubFolder::getId() const { return _id; }
2323

2424
int NoteSubFolder::getParentId() const { return _parentId; }
2525

26-
NoteSubFolder NoteSubFolder::getParent() const { return NoteSubFolder::fetch(_parentId); }
26+
NoteSubFolder NoteSubFolder::getParent(const QString &connectionName) const {
27+
return NoteSubFolder::fetch(_parentId, connectionName);
28+
}
2729

2830
QString NoteSubFolder::getName() const { return _name; }
2931

@@ -37,22 +39,62 @@ void NoteSubFolder::setParentId(int parentId) { _parentId = parentId; }
3739

3840
bool NoteSubFolder::isFetched() const { return (_id > 0); }
3941

40-
NoteSubFolder NoteSubFolder::fetch(int id) {
41-
const QSqlDatabase db = QSqlDatabase::database(QStringLiteral("memory"));
42-
QSqlQuery query(db);
42+
NoteSubFolder NoteSubFolder::fetch(int id, const QString &connectionName) {
43+
auto noteSubFolder = NoteSubFolder();
44+
// bool closeDb = connectionName != QStringLiteral("memory");
45+
bool closeDb = false;
4346

44-
query.prepare(QStringLiteral("SELECT * FROM noteSubFolder WHERE id = :id"));
45-
query.bindValue(QStringLiteral(":id"), id);
47+
{
48+
// QSqlDatabase db = DatabaseService::getSharedMemoryDatabase(connectionName);
49+
qDebug() << __func__ << " - 'connectionName': " << connectionName;
50+
qDebug() << __func__ << " - 'id': " << id;
4651

47-
if (!query.exec()) {
48-
qWarning() << __func__ << ": " << query.lastError();
49-
} else {
50-
if (query.first()) {
51-
return noteSubFolderFromQuery(query);
52+
// if (connectionName == QStringLiteral("memory")) {
53+
// void* array[50];
54+
// int size = backtrace(array, 50);
55+
// char** messages = backtrace_symbols(array, size);
56+
//
57+
// // Print the stack trace
58+
// for (int i = 0; i < size && messages != nullptr; ++i) {
59+
// qDebug() << "[" << i << "]" << messages[i];
60+
// }
61+
// free(messages);
62+
// }
63+
64+
const QSqlDatabase db = QSqlDatabase::database(connectionName);
65+
66+
// if (!db.open()) {
67+
// qWarning() << "Failed to open database in thread:" << db.lastError().text();
68+
// if (closeDb) {
69+
// QSqlDatabase::removeDatabase(connectionName);
70+
// }
71+
// return {};
72+
// }
73+
74+
QSqlQuery query(db);
75+
query.prepare(QStringLiteral("SELECT * FROM noteSubFolder WHERE id = :id"));
76+
query.bindValue(QStringLiteral(":id"), id);
77+
78+
if (!query.exec()) {
79+
qWarning() << __func__ << ": " << query.lastError();
80+
} else {
81+
if (query.first()) {
82+
noteSubFolder = noteSubFolderFromQuery(query);
83+
}
5284
}
85+
86+
query.finish();
87+
88+
// if (closeDb) {
89+
// db.close();
90+
// }
91+
} // db goes out of scope here
92+
93+
if (closeDb) {
94+
QSqlDatabase::removeDatabase(connectionName);
5395
}
5496

55-
return NoteSubFolder();
97+
return noteSubFolder;
5698
}
5799

58100
NoteSubFolder NoteSubFolder::fetchByNameAndParentId(const QString& name, int parentId) {
@@ -79,8 +121,8 @@ NoteSubFolder NoteSubFolder::fetchByNameAndParentId(const QString& name, int par
79121
/**
80122
* Gets the relative path name of the note sub folder
81123
*/
82-
QString NoteSubFolder::relativePath(char separator) const {
83-
return _parentId == 0 ? _name : getParent().relativePath(separator) + separator + _name;
124+
QString NoteSubFolder::relativePath(char separator, const QString &connectionName) const {
125+
return _parentId == 0 ? _name : getParent(connectionName).relativePath(separator) + separator + _name;
84126
}
85127

86128
/**

src/entities/notesubfolder.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class NoteSubFolder {
1919

2020
void setName(QString text);
2121

22-
static NoteSubFolder fetch(int id);
22+
static NoteSubFolder fetch(int id, const QString &connectionName = QStringLiteral("memory"));
2323

2424
static QVector<NoteSubFolder> fetchAll(int limit = -1);
2525

@@ -49,11 +49,11 @@ class NoteSubFolder {
4949

5050
void setParentId(int parentId);
5151

52-
QString relativePath(char separator = '/') const;
52+
QString relativePath(char separator = '/', const QString &connectionName = QStringLiteral("memory")) const;
5353

5454
QString fullPath() const;
5555

56-
NoteSubFolder getParent() const;
56+
NoteSubFolder getParent(const QString &connectionName = QStringLiteral("memory")) const;
5757

5858
static QVector<NoteSubFolder> fetchAllByParentId(
5959
int parentId, const QString& sortBy = QStringLiteral("file_last_modified DESC"));

src/services/databaseservice.cpp

+22-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <QSqlError>
1515
#include <QSqlQuery>
1616
#include <QStandardPaths>
17+
#include <QUuid>
1718

1819
#include "entities/calendaritem.h"
1920
#include "mainwindow.h"
@@ -95,10 +96,28 @@ bool DatabaseService::checkDiskDatabaseIntegrity() {
9596
return false;
9697
}
9798

99+
QString DatabaseService::generateConnectionName() {
100+
// return "memory";
101+
return QString("connection-%1").arg(QUuid::createUuid().toString());
102+
}
103+
104+
QSqlDatabase DatabaseService::createSharedMemoryDatabase(const QString& connectionName) {
105+
QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), connectionName);
106+
db.setDatabaseName(QStringLiteral("file:memory?mode=memory&cache=shared"));
107+
// db.setDatabaseName(QStringLiteral(":memory:"));
108+
db.setConnectOptions("QSQLITE_OPEN_URI");
109+
110+
return db;
111+
}
112+
113+
QSqlDatabase DatabaseService::getSharedMemoryDatabase(const QString& connectionName) {
114+
return connectionName == QStringLiteral("memory") ?
115+
QSqlDatabase::database(QStringLiteral("memory")) :
116+
createSharedMemoryDatabase(connectionName);
117+
}
118+
98119
bool DatabaseService::createMemoryConnection() {
99-
QSqlDatabase dbMemory =
100-
QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), QStringLiteral("memory"));
101-
dbMemory.setDatabaseName(QStringLiteral(":memory:"));
120+
QSqlDatabase dbMemory = createSharedMemoryDatabase(QStringLiteral("memory"));
102121

103122
if (!dbMemory.open()) {
104123
QMessageBox::critical(nullptr, QWidget::tr("Cannot open memory database"),

src/services/databaseservice.h

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class DatabaseService {
2525
static bool mergeNoteFolderDatabase(const QString& path);
2626
static QByteArray generateDatabaseTableSha1Signature(QSqlDatabase& db, const QString& table);
2727
static bool checkDiskDatabaseIntegrity();
28+
static QString generateConnectionName();
29+
static QSqlDatabase createSharedMemoryDatabase(const QString& connectionName = QStringLiteral("memory"));
30+
static QSqlDatabase getSharedMemoryDatabase(const QString& connectionName = QStringLiteral("memory"));
2831

2932
private:
3033
static bool createMemoryConnection();

src/widgets/noterelationscene.cpp

+18-8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <cmath>
2323

2424
#include "mainwindow.h"
25+
#include "services/databaseservice.h"
2526

2627
// NoteItem Implementation
2728
NoteItem::NoteItem(Note &note, qreal x, qreal y, qreal width, qreal height, int level,
@@ -145,10 +146,15 @@ void NoteRelationScene::drawForNote(const Note& note) {
145146
clear();
146147
const auto noteList = Note::fetchAll();
147148

148-
//#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
149-
// QFuture<void> future = QtConcurrent::run([this, note, noteList]() {
149+
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
150+
QFuture<void> future = QtConcurrent::run([this, note, noteList]() {
151+
const QString connectionName = DatabaseService::generateConnectionName();
152+
qDebug() << __func__ << " - 'connectionName': " << connectionName;
153+
154+
QSqlDatabase db = DatabaseService::createSharedMemoryDatabase(connectionName);
155+
150156
auto rootNoteItem = createNoteItem(QPointF(100, 100), note);
151-
createLinkedNoteItems(noteList, note, rootNoteItem);
157+
createLinkedNoteItems(noteList, connectionName, note, rootNoteItem);
152158

153159
// Update all connections
154160
for (auto connection : m_connections) {
@@ -157,12 +163,16 @@ void NoteRelationScene::drawForNote(const Note& note) {
157163

158164
// Update the scene
159165
update();
160-
// });
161-
//#endif
166+
167+
db.close();
168+
QSqlDatabase::removeDatabase(connectionName);
169+
qDebug() << __func__ << " - 'connectionName' closed: " << connectionName;
170+
});
171+
#endif
162172
}
163173

164-
void NoteRelationScene::createLinkedNoteItems(const QVector<Note>& noteList, Note note, NoteItem *rootNoteItem, int level) {
165-
auto linkedNotes = note.findLinkedNotes(noteList);
174+
void NoteRelationScene::createLinkedNoteItems(const QVector<Note>& noteList, const QString &connectionName, Note note, NoteItem *rootNoteItem, int level) {
175+
auto linkedNotes = note.findLinkedNotes(noteList, connectionName);
166176

167177
// Get root note position (center)
168178
QPointF rootCenter = rootNoteItem->pos() + rootNoteItem->rect().center();
@@ -191,7 +201,7 @@ void NoteRelationScene::createLinkedNoteItems(const QVector<Note>& noteList, Not
191201
createConnection(rootNoteItem, linkedNoteItem);
192202

193203
if (level < 3) {
194-
createLinkedNoteItems(noteList, linkedNote, linkedNoteItem, level);
204+
createLinkedNoteItems(noteList, connectionName, linkedNote, linkedNoteItem, level);
195205
}
196206

197207
index++;

src/widgets/noterelationscene.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,5 @@ class NoteRelationScene : public QGraphicsScene {
7373
NoteItem *m_startItem;
7474
std::vector<ConnectionLine *> m_connections;
7575
static QPointF calculateRadialPosition(QPointF center, int index, int total, qreal radius);
76-
void createLinkedNoteItems(const QVector<Note>& noteList, Note note, NoteItem *rootNoteItem, int level = 0);
76+
void createLinkedNoteItems(const QVector<Note>& noteList, const QString &connectionName, Note note, NoteItem *rootNoteItem, int level = 0);
7777
};

0 commit comments

Comments
 (0)