@@ -69,21 +69,20 @@ synchronization here.
69
69
\section2 Parallelism/Theading
70
70
Most operations are not parallel and usually take place in the main thread (but are still thread
71
71
safe).
72
- There are two main task that are executed in parallel: Indexing, and OpenDocumentUpdate.
73
- Indexing is meant to keep the global view up to date.
72
+ There is one task that is executed in parallel: OpenDocumentUpdate.
74
73
OpenDocumentUpdate keeps the snapshots of the open documents up to date.
75
74
76
75
There is always a tension between being responsive, using all threads available, and avoid to hog
77
76
too many resources. One can choose different parallelization strategies, we went with a flexiable
78
77
approach.
79
- We have (private) functions that execute part of the work: indexSome() and openUpdateSome(). These
78
+ We have (private) functions that execute part of the work: openUpdateSome(). These
80
79
do all locking needed, get some work, do it without locks, and at the end update the state of the
81
80
code model. If there is more work, then they return true. Thus while (xxxSome()); works until there
82
81
is no work left.
83
82
84
- addDirectoriesToIndex(), the internal addDirectory() and addOpenToUpdate() add more work to do.
83
+ The internal addOpenToUpdate() add more work to do.
85
84
86
- indexNeedsUpdate() and openNeedUpdate(), check if there is work to do, and if yes ensure that a
85
+ openNeedUpdate() checks if there is work to do, and if yes ensure that a
87
86
worker thread (or more) that work on it exist.
88
87
*/
89
88
@@ -119,7 +118,7 @@ QQmlCodeModel::~QQmlCodeModel()
119
118
QMutexLocker l (&m_mutex);
120
119
m_state = State::Stopping;
121
120
m_openDocumentsToUpdate.clear ();
122
- shouldWait = m_nIndexInProgress != 0 || m_nUpdateInProgress != 0 ;
121
+ shouldWait = m_nUpdateInProgress != 0 ;
123
122
}
124
123
if (!shouldWait)
125
124
break ;
@@ -132,143 +131,8 @@ OpenDocumentSnapshot QQmlCodeModel::snapshotByUrl(const QByteArray &url)
132
131
return openDocumentByUrl (url).snapshot ;
133
132
}
134
133
135
- int QQmlCodeModel::indexEvalProgress () const
136
- {
137
- Q_ASSERT (!m_mutex.tryLock ()); // should be called while locked
138
- const int dirCost = 10 ;
139
- int costToDo = 1 ;
140
- for (const ToIndex &el : std::as_const (m_toIndex))
141
- costToDo += dirCost * el.leftDepth ;
142
- costToDo += m_indexInProgressCost;
143
- return m_indexDoneCost * 100 / (costToDo + m_indexDoneCost);
144
- }
145
-
146
- void QQmlCodeModel::indexStart ()
147
- {
148
- Q_ASSERT (!m_mutex.tryLock ()); // should be called while locked
149
- qCDebug (codeModelLog) << " indexStart" ;
150
- }
151
-
152
- void QQmlCodeModel::indexEnd ()
153
- {
154
- Q_ASSERT (!m_mutex.tryLock ()); // should be called while locked
155
- qCDebug (codeModelLog) << " indexEnd" ;
156
- m_lastIndexProgress = 0 ;
157
- m_nIndexInProgress = 0 ;
158
- m_toIndex.clear ();
159
- m_indexInProgressCost = 0 ;
160
- m_indexDoneCost = 0 ;
161
- }
162
-
163
- void QQmlCodeModel::indexSendProgress (int progress)
164
- {
165
- if (progress <= m_lastIndexProgress)
166
- return ;
167
- m_lastIndexProgress = progress;
168
- // ### actually send progress
169
- }
170
-
171
- bool QQmlCodeModel::indexCancelled ()
172
- {
173
- QMutexLocker l (&m_mutex);
174
- if (m_state == State::Stopping)
175
- return true ;
176
- return false ;
177
- }
178
-
179
- void QQmlCodeModel::indexDirectory (const QString &path, int depthLeft)
180
- {
181
- if (indexCancelled ())
182
- return ;
183
- QDir dir (path);
184
- if (depthLeft > 1 ) {
185
- const QStringList dirs =
186
- dir.entryList (QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
187
- for (const QString &child : dirs)
188
- addDirectory (dir.filePath (child), --depthLeft);
189
- }
190
- const QStringList qmljs =
191
- dir.entryList (QStringList ({ u" *.qml" _s, u" *.js" _s, u" *.mjs" _s }), QDir::Files);
192
- int progress = 0 ;
193
- {
194
- QMutexLocker l (&m_mutex);
195
- m_indexInProgressCost += qmljs.size ();
196
- progress = indexEvalProgress ();
197
- }
198
- indexSendProgress (progress);
199
- if (qmljs.isEmpty ())
200
- return ;
201
- DomItem newCurrent = m_currentEnv.makeCopy (DomItem::CopyOption::EnvConnected).item ();
202
- for (const QString &file : qmljs) {
203
- if (indexCancelled ())
204
- return ;
205
- QString fPath = dir.filePath (file);
206
- auto newCurrentPtr = newCurrent.ownerAs <DomEnvironment>();
207
- FileToLoad fileToLoad = FileToLoad::fromFileSystem (newCurrentPtr, fPath );
208
- if (!fileToLoad.canonicalPath ().isEmpty ()) {
209
- newCurrentPtr->loadBuiltins ();
210
- newCurrentPtr->loadFile (fileToLoad, [](Path, const DomItem &, const DomItem &) {});
211
- newCurrentPtr->loadPendingDependencies ();
212
- newCurrent.commitToBase (m_validEnv.ownerAs <DomEnvironment>());
213
- }
214
- {
215
- QMutexLocker l (&m_mutex);
216
- ++m_indexDoneCost;
217
- --m_indexInProgressCost;
218
- progress = indexEvalProgress ();
219
- }
220
- indexSendProgress (progress);
221
- }
222
- }
223
-
224
- void QQmlCodeModel::addDirectoriesToIndex (const QStringList &paths, QLanguageServer *server)
225
- {
226
- Q_UNUSED (server);
227
- // ### create progress, &scan in a separate instance
228
- const int maxDepth = 5 ;
229
- for (const auto &path : paths)
230
- addDirectory (path, maxDepth);
231
- indexNeedsUpdate ();
232
- }
233
-
234
- void QQmlCodeModel::addDirectory (const QString &path, int depthLeft)
235
- {
236
- if (depthLeft < 1 )
237
- return ;
238
- {
239
- QMutexLocker l (&m_mutex);
240
- for (auto it = m_toIndex.begin (); it != m_toIndex.end ();) {
241
- if (it->path .startsWith (path)) {
242
- if (it->path .size () == path.size ())
243
- return ;
244
- if (it->path .at (path.size ()) == u' /' ) {
245
- it = m_toIndex.erase (it);
246
- continue ;
247
- }
248
- } else if (path.startsWith (it->path ) && path.at (it->path .size ()) == u' /' )
249
- return ;
250
- ++it;
251
- }
252
- m_toIndex.append ({ path, depthLeft });
253
- }
254
- }
255
-
256
134
void QQmlCodeModel::removeDirectory (const QString &path)
257
135
{
258
- {
259
- QMutexLocker l (&m_mutex);
260
- auto toRemove = [path](const QString &p) {
261
- return p.startsWith (path) && (p.size () == path.size () || p.at (path.size ()) == u' /' );
262
- };
263
- auto it = m_toIndex.begin ();
264
- auto end = m_toIndex.end ();
265
- while (it != end) {
266
- if (toRemove (it->path ))
267
- it = m_toIndex.erase (it);
268
- else
269
- ++it;
270
- }
271
- }
272
136
if (auto validEnvPtr = m_validEnv.ownerAs <DomEnvironment>())
273
137
validEnvPtr->removePath (path);
274
138
if (auto currentEnvPtr = m_currentEnv.ownerAs <DomEnvironment>())
@@ -332,59 +196,13 @@ const RegisteredSemanticTokens &QQmlCodeModel::registeredTokens() const
332
196
return m_tokens;
333
197
}
334
198
335
- void QQmlCodeModel::indexNeedsUpdate ()
336
- {
337
- const int maxIndexThreads = 1 ;
338
- {
339
- QMutexLocker l (&m_mutex);
340
- if (m_toIndex.isEmpty () || m_nIndexInProgress >= maxIndexThreads)
341
- return ;
342
- if (++m_nIndexInProgress == 1 )
343
- indexStart ();
344
- }
345
- QThreadPool::globalInstance ()->start ([this ]() {
346
- while (indexSome ()) { }
347
- });
348
- }
349
-
350
- bool QQmlCodeModel::indexSome ()
351
- {
352
- qCDebug (codeModelLog) << " indexSome" ;
353
- ToIndex toIndex;
354
- {
355
- QMutexLocker l (&m_mutex);
356
- if (m_toIndex.isEmpty ()) {
357
- if (--m_nIndexInProgress == 0 )
358
- indexEnd ();
359
- return false ;
360
- }
361
- toIndex = m_toIndex.last ();
362
- m_toIndex.removeLast ();
363
- }
364
- bool hasMore = false ;
365
- {
366
- auto guard = qScopeGuard ([this , &hasMore]() {
367
- QMutexLocker l (&m_mutex);
368
- if (m_toIndex.isEmpty ()) {
369
- if (--m_nIndexInProgress == 0 )
370
- indexEnd ();
371
- hasMore = false ;
372
- } else {
373
- hasMore = true ;
374
- }
375
- });
376
- indexDirectory (toIndex.path , toIndex.leftDepth );
377
- }
378
- return hasMore;
379
- }
380
-
381
199
void QQmlCodeModel::openNeedUpdate ()
382
200
{
383
201
qCDebug (codeModelLog) << " openNeedUpdate" ;
384
- const int maxIndexThreads = 1 ;
202
+ const int maxThreads = 1 ;
385
203
{
386
204
QMutexLocker l (&m_mutex);
387
- if (m_openDocumentsToUpdate.isEmpty () || m_nUpdateInProgress >= maxIndexThreads )
205
+ if (m_openDocumentsToUpdate.isEmpty () || m_nUpdateInProgress >= maxThreads )
388
206
return ;
389
207
if (++m_nUpdateInProgress == 1 )
390
208
openUpdateStart ();
0 commit comments