diff --git a/src/parser/Parser.cpp b/src/parser/Parser.cpp index f408dba74439169fc990021440f172a72fb84527..4142200f8113b17cd6c2f1e04161986ba493c44a 100644 --- a/src/parser/Parser.cpp +++ b/src/parser/Parser.cpp @@ -45,6 +45,7 @@ Parser::Parser( MediaLibrary* ml, FsHolder* fsHolder ) , m_callback( nullptr ) , m_opScheduled( 0 ) , m_opDone( 0 ) + , m_completionSignaled( false ) { } @@ -197,11 +198,20 @@ void Parser::updateStats() if ( m_callback == nullptr ) return; assert( m_opScheduled >= m_opDone ); - if ( m_opDone % 10 == 0 || m_opScheduled == m_opDone ) + /* + * We don't want to spam the callback receiver each time we're done parsing + * an item, however we must signal progress when: + * - All tasks have been processed + * - We signaled that all tasks were processed before, and we have new tasks + * to process now. + */ + if ( m_opDone % 10 == 0 || m_opScheduled == m_opDone || + m_completionSignaled == true ) { LOG_DEBUG( "Updating progress: operations scheduled ", m_opScheduled, "; operations done: ", m_opDone ); m_callback->onParsingStatsUpdated( m_opDone, m_opScheduled ); + m_completionSignaled = m_opScheduled == m_opDone; } } diff --git a/src/parser/Parser.h b/src/parser/Parser.h index 8139f0fe205954276da6453f01707bac9be85c80..3dc55a0f2e9c784e8c7fef4b72ee486f68d26b0a 100644 --- a/src/parser/Parser.h +++ b/src/parser/Parser.h @@ -104,6 +104,7 @@ private: IMediaLibraryCb* m_callback; uint32_t m_opScheduled; uint32_t m_opDone; + bool m_completionSignaled; }; } diff --git a/test/samples/Tester.cpp b/test/samples/Tester.cpp index 99f9b1fb03534b8f66eb09cca13d4aebc412b453..c2f70dfb8e43f75882cff65c1fbcf8f5e6f96e72 100644 --- a/test/samples/Tester.cpp +++ b/test/samples/Tester.cpp @@ -56,11 +56,11 @@ MockCallback::MockCallback() { } -bool MockCallback::waitForParsingComplete() +void MockCallback::waitForParsingComplete() { std::unique_lock lock{ m_parsingMutex }; // Wait for a while, generating snapshots can be heavy... - return m_parsingCompleteVar.wait_for( lock, std::chrono::seconds{ 20 }, [this]() { + m_parsingCompleteVar.wait( lock, [this]() { return m_parserDone && m_discoveryCompleted; }); } @@ -109,7 +109,6 @@ void MockCallback::onDiscoveryCompleted() { std::lock_guard lock( m_parsingMutex ); m_discoveryCompleted = true; - m_parsingCompleteVar.notify_all(); } void MockCallback::onParsingStatsUpdated( uint32_t done, uint32_t scheduled ) @@ -117,10 +116,6 @@ void MockCallback::onParsingStatsUpdated( uint32_t done, uint32_t scheduled ) std::lock_guard lock( m_parsingMutex ); m_parserDone = done == scheduled; - if ( m_parserDone == false ) - return; - - m_parsingCompleteVar.notify_all(); } void MockCallback::onMediaThumbnailReady( MediaPtr media, ThumbnailSizeType, @@ -143,6 +138,12 @@ void MockCallback::onEntryPointRemoved( const std::string& entryPoint, bool ) if ( --m_nbEntryPointsRemovalExpected > 0 ) return; m_removalCompleted = true; +} + +void MockCallback::onBackgroundTasksIdleChanged( bool idle ) +{ + if ( idle == false ) + return; m_parsingCompleteVar.notify_all(); } @@ -160,22 +161,21 @@ void MockResumeCallback::reinit() m_parserDone = false; } -bool MockResumeCallback::waitForDiscoveryComplete() +void MockResumeCallback::waitForDiscoveryComplete() { std::unique_lock lock{ m_parsingMutex }; - return m_discoveryCompletedVar.wait_for( lock, std::chrono::seconds{ 20 }, [this]() { + m_discoveryCompletedVar.wait( lock, [this]() { return m_discoveryCompleted; }); } -bool MockResumeCallback::waitForParsingComplete() +void MockResumeCallback::waitForParsingComplete() { std::unique_lock lock{ m_parsingMutex }; // Reimplement without checking for discovery complete. This class is meant to be used // in 2 steps: waiting for discovery completed, then for parsing completed assert( m_discoveryCompleted == true ); - // Wait for a while, generating snapshots can be heavy... - return m_parsingCompleteVar.wait_for( lock, std::chrono::seconds{ 20 }, [this]() { + m_parsingCompleteVar.wait( lock, [this]() { return m_parserDone; }); } @@ -917,11 +917,11 @@ void MockCallback::prepareForPlaylistReload() m_parserDone = false; } -bool MockCallback::waitForPlaylistReload() +void MockCallback::waitForPlaylistReload() { std::unique_lock lock{ m_parsingMutex }; // Wait for a while, generating snapshots can be heavy... - return m_parsingCompleteVar.wait_for( lock, std::chrono::seconds{ 20 }, [this]() { + m_parsingCompleteVar.wait( lock, [this]() { return m_parserDone; }); } diff --git a/test/samples/Tester.h b/test/samples/Tester.h index c6b9d7c06b81b8b62100372ef28524551b7e1745..43c12017112379738ca5782614738e6c0a022b7e 100644 --- a/test/samples/Tester.h +++ b/test/samples/Tester.h @@ -49,14 +49,14 @@ class MockCallback : public mock::NoopCallback { public: MockCallback(); - virtual bool waitForParsingComplete(); - virtual bool waitForDiscoveryComplete() { return true; } + virtual void waitForParsingComplete(); + virtual void waitForDiscoveryComplete() {} virtual bool waitForRemovalComplete(); virtual void reinit(); void prepareWaitForThumbnail( MediaPtr media ); bool waitForThumbnail(); void prepareForPlaylistReload(); - bool waitForPlaylistReload(); + void waitForPlaylistReload(); void prepareForDiscovery( uint32_t nbEntryPointsExpected ); void prepareForRemoval( uint32_t nbEntryPointsRemovalExpected ); @@ -67,6 +67,7 @@ protected: virtual void onMediaThumbnailReady( MediaPtr media, ThumbnailSizeType sizeType, bool success ) override; virtual void onEntryPointRemoved( const std::string& entryPoint, bool res ) override; + virtual void onBackgroundTasksIdleChanged( bool idle ) override; compat::ConditionVariable m_parsingCompleteVar; compat::Mutex m_parsingMutex; @@ -84,8 +85,8 @@ protected: class MockResumeCallback : public MockCallback { public: - virtual bool waitForDiscoveryComplete() override; - virtual bool waitForParsingComplete() override; + virtual void waitForDiscoveryComplete() override; + virtual void waitForParsingComplete() override; virtual void onDiscoveryCompleted() override; virtual void reinit() override; diff --git a/test/samples/main.cpp b/test/samples/main.cpp index db5edcf6356aaa845ba097e701448df0ea0d9957..2c5e7769a1e3a41118fbc87986a68970d1a50a4d 100644 --- a/test/samples/main.cpp +++ b/test/samples/main.cpp @@ -37,14 +37,14 @@ static void Parse( Tests* T ) { - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->runChecks(); } static void ParseTwice( Tests* T ) { - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->runChecks(); @@ -66,46 +66,46 @@ static void ParseTwice( Tests* T ) T->m_ml->discover( utils::file::toMrl( samplesDir ) ); } - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->runChecks(); } static void RunResumeTests( ResumeTests* T ) { - ASSERT_TRUE( T->m_cb->waitForDiscoveryComplete() ); + T->m_cb->waitForDiscoveryComplete(); auto testMl = static_cast( T->m_ml.get() ); testMl->forceParserStart(); - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->runChecks(); } static void Rescan( ResumeTests* T ) { - ASSERT_TRUE( T->m_cb->waitForDiscoveryComplete() ); + T->m_cb->waitForDiscoveryComplete(); auto testMl = static_cast( T->m_ml.get() ); testMl->forceParserStart(); - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->m_cb->reinit(); T->m_ml->forceRescan(); - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->runChecks(); } static void RunRefreshTests( RefreshTests* T ) { - ASSERT_TRUE( T->m_cb->waitForDiscoveryComplete() ); - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForDiscoveryComplete(); + T->m_cb->waitForParsingComplete(); T->runChecks(); T->m_cb->reinit(); T->forceRefresh(); - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->runChecks(); } @@ -116,7 +116,7 @@ static void ReplaceVlcInstance( Tests* T ) T->m_ml->setExternalLibvlcInstance( inst.get() ); /* Replacing the instance will stop the discoverer so let's resume it */ T->m_ml->reload(); - ASSERT_TRUE( T->m_cb->waitForParsingComplete() ); + T->m_cb->waitForParsingComplete(); T->runChecks(); } @@ -127,8 +127,7 @@ static void RunBackupRestorePlaylist( BackupRestorePlaylistTests* T ) ASSERT_TRUE( utils::fs::isDirectory( samplesFolder ) ); samplesFolder = utils::fs::toAbsolute( samplesFolder ); T->m_ml->discover( utils::file::toMrl( samplesFolder ) ); - auto res = T->m_cb->waitForParsingComplete(); - ASSERT_TRUE( res ); + T->m_cb->waitForParsingComplete(); // Now we should have discovered some media auto media = T->m_ml->audioFiles( nullptr )->all(); @@ -154,8 +153,7 @@ static void RunBackupRestorePlaylist( BackupRestorePlaylistTests* T ) T->m_cb->prepareForPlaylistReload(); T->m_ml->clearDatabase( true ); - res = T->m_cb->waitForPlaylistReload(); - ASSERT_TRUE( res ); + T->m_cb->waitForPlaylistReload(); auto playlists = T->m_ml->playlists( PlaylistType::All, nullptr )->all(); ASSERT_EQ( 2u, playlists.size() ); @@ -178,8 +176,7 @@ static void RunBackupRestorePlaylist( BackupRestorePlaylistTests* T ) */ T->m_cb->reinit(); T->m_ml->discover( utils::file::toMrl( samplesFolder ) ); - res = T->m_cb->waitForParsingComplete(); - ASSERT_TRUE( res ); + T->m_cb->waitForParsingComplete(); media = playlist1->media( nullptr )->all(); ASSERT_EQ( m1->title(), media[0]->title() ); ASSERT_EQ( m2->title(), media[1]->title() );