Navigation Menu

Skip to content

Commit

Permalink
[browser] By default do not monitor directories on drives we know
Browse files Browse the repository at this point in the history
are slow

Effectively this means that the browser no longer defaults to watching
network and remote drives (on Windows) for changes. This is expensive
to do and can result in large hangs in the QGIS application.

Users can still manually opt-in to monitoring of these locations
through the context menu of the directory in the browser panel.
  • Loading branch information
nyalldawson committed May 31, 2021
1 parent 75838d3 commit 8ff0efd
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 4 deletions.
2 changes: 2 additions & 0 deletions cmake_templates/qgsconfig.h.in
Expand Up @@ -97,5 +97,7 @@
#define PDAL_VERSION_MINOR "${PDAL_VERSION_MINOR}"
#define PDAL_VERSION_MICRO "${PDAL_VERSION_MICRO}"

#cmakedefine ENABLE_TESTS

#endif

5 changes: 3 additions & 2 deletions python/core/auto_generated/browser/qgsdirectoryitem.sip.in
Expand Up @@ -142,8 +142,9 @@ All parent directories will be checked to determine whether they have monitoring
manually enabled or disabled. As soon as a parent directory is found which has monitoring
manually enabled or disabled then the corresponding value will be returned.

Paths are monitored by default, so if no explicit setting is in place for a parent directory then
the function will return ``True``.
If no explicit setting is in place for a parent directory, then a check will be made to determine
whether the path resides on a known slow drive. If so, monitoring is disabled by default and
``False`` will be returned. Otherwise paths are monitored by default and the function will return ``True``.

.. seealso:: :py:func:`isMonitored`

Expand Down
6 changes: 6 additions & 0 deletions src/core/browser/qgsdirectoryitem.cpp
Expand Up @@ -23,6 +23,7 @@
#include "qgsdataprovider.h"
#include "qgszipitem.h"
#include "qgsprojectitem.h"
#include "qgsfileutils.h"
#include <QFileSystemWatcher>
#include <QDir>
#include <QMouseEvent>
Expand Down Expand Up @@ -449,6 +450,11 @@ bool QgsDirectoryItem::pathShouldByMonitoredByDefault( const QString &path )
}
}

// else if we know that the path is on a slow device, we don't monitor by default
// as this can be very expensive and slow down QGIS
if ( QgsFileUtils::pathIsSlowDevice( path ) )
return false;

// paths are monitored by default if no explicit setting is in place
return true;
}
Expand Down
5 changes: 3 additions & 2 deletions src/core/browser/qgsdirectoryitem.h
Expand Up @@ -150,8 +150,9 @@ class CORE_EXPORT QgsDirectoryItem : public QgsDataCollectionItem
* manually enabled or disabled. As soon as a parent directory is found which has monitoring
* manually enabled or disabled then the corresponding value will be returned.
*
* Paths are monitored by default, so if no explicit setting is in place for a parent directory then
* the function will return TRUE.
* If no explicit setting is in place for a parent directory, then a check will be made to determine
* whether the path resides on a known slow drive. If so, monitoring is disabled by default and
* FALSE will be returned. Otherwise paths are monitored by default and the function will return TRUE.
*
* \see isMonitored()
* \see setMonitoring()
Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsfileutils.cpp
Expand Up @@ -15,6 +15,7 @@
#include "qgsfileutils.h"
#include "qgis.h"
#include "qgsexception.h"
#include "qgsconfig.h"
#include <QObject>
#include <QRegularExpression>
#include <QFileInfo>
Expand Down Expand Up @@ -337,6 +338,11 @@ Qgis::DriveType QgsFileUtils::driveType( const QString &path )

bool QgsFileUtils::pathIsSlowDevice( const QString &path )
{
#ifdef ENABLE_TESTS
if ( path.contains( QLatin1String( "fake_slow_path_for_unit_tests" ) ) )
return true;
#endif

try
{
const Qgis::DriveType type = driveType( path );
Expand Down
52 changes: 52 additions & 0 deletions tests/src/core/testqgsdataitem.cpp
Expand Up @@ -53,6 +53,7 @@ class TestQgsDataItem : public QObject
void testDirItem();
void testDirItemChildren();
void testDirItemMonitoring();
void testDirItemMonitoringSlowDrive();
void testLayerItemType();
void testProjectItemCreation();

Expand Down Expand Up @@ -341,6 +342,57 @@ void TestQgsDataItem::testDirItemMonitoring()
QVERIFY( !childItem3->mFileSystemWatcher );
}

void TestQgsDataItem::testDirItemMonitoringSlowDrive()
{
QTemporaryDir dir;

// fake a directory on a slow drive -- this is a special hardcoded path which always reports to be on a slow drive. See QgsFileUtils::pathIsSlowDevice
const QString parentDir = dir.path() + QStringLiteral( "/fake_slow_path_for_unit_tests" );
const QString child1 = parentDir + QStringLiteral( "/child1" );
QVERIFY( QDir().mkpath( child1 ) );
const QString child2 = parentDir + QStringLiteral( "/child2" );
QVERIFY( QDir().mkpath( child2 ) );
const QString child2child = child2 + QStringLiteral( "/child" );
QVERIFY( QDir().mkpath( child2child ) );

QVERIFY( !QgsDirectoryItem::pathShouldByMonitoredByDefault( parentDir ) );
QVERIFY( !QgsDirectoryItem::pathShouldByMonitoredByDefault( child1 ) );
QVERIFY( !QgsDirectoryItem::pathShouldByMonitoredByDefault( child2 ) );
QVERIFY( !QgsDirectoryItem::pathShouldByMonitoredByDefault( child2child ) );

std::unique_ptr< QgsDirectoryItem > dirItem = std::make_unique< QgsDirectoryItem >( nullptr, QStringLiteral( "parent name" ), parentDir, QStringLiteral( "/" ) + parentDir );
// user has not explicitly set the path to be monitored or not, so Default should be returned here:
QCOMPARE( dirItem->monitoring(), Qgis::BrowserDirectoryMonitoring::Default );
// but directory should NOT be monitored
QVERIFY( !dirItem->isMonitored() );

dirItem->populate( true );
QVERIFY( !dirItem->mFileSystemWatcher );

QCOMPARE( dirItem->rowCount(), 2 );
QPointer< QgsDirectoryItem > childItem1( qobject_cast< QgsDirectoryItem * >( dirItem->children().at( 0 ) ) );
QPointer< QgsDirectoryItem > childItem2( qobject_cast< QgsDirectoryItem * >( dirItem->children().at( 1 ) ) );
QVERIFY( childItem1 );
QVERIFY( childItem2 );
// neither of these should be monitored either!
QVERIFY( !childItem1->isMonitored() );
QVERIFY( !childItem2->isMonitored() );
childItem1->populate( true );
childItem2->populate( true );
QVERIFY( !childItem1->mFileSystemWatcher );
QVERIFY( !childItem2->mFileSystemWatcher );

// explicitly opt in to monitoring a directory on a slow drive
childItem2->setMonitoring( Qgis::BrowserDirectoryMonitoring::AlwaysMonitor );
QVERIFY( childItem2->mFileSystemWatcher );

// this means that subdirectories of childItem2 should now return true to being monitored by default
QVERIFY( !QgsDirectoryItem::pathShouldByMonitoredByDefault( parentDir ) );
QVERIFY( !QgsDirectoryItem::pathShouldByMonitoredByDefault( child1 ) );
QVERIFY( !QgsDirectoryItem::pathShouldByMonitoredByDefault( child2 ) );
QVERIFY( QgsDirectoryItem::pathShouldByMonitoredByDefault( child2child ) );
}

void TestQgsDataItem::testLayerItemType()
{
std::unique_ptr< QgsMapLayer > layer = std::make_unique< QgsVectorLayer >( mTestDataDir + "polys.shp",
Expand Down

0 comments on commit 8ff0efd

Please sign in to comment.