Prevent the media scanner from never quitting
This commit is contained in:
@@ -420,7 +420,10 @@ MediaScanner::scan(boost::system::error_code err)
|
||||
{
|
||||
for (auto& addon : _addons)
|
||||
addon->preScanComplete();
|
||||
}
|
||||
|
||||
if (_running)
|
||||
{
|
||||
stats.stopTime = Wt::WLocalDateTime::currentDateTime().toUTC();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock {_statusMutex};
|
||||
@@ -471,6 +474,13 @@ MediaScanner::refreshScanSettings()
|
||||
addon->refreshSettings();
|
||||
}
|
||||
|
||||
void MediaScanner::notifyInProgress(Stats& stats)
|
||||
{
|
||||
std::chrono::system_clock::time_point now {std::chrono::system_clock::now()};
|
||||
_sigScanInProgress(stats);
|
||||
_lastScanInProgressEmit = now;
|
||||
}
|
||||
|
||||
void MediaScanner::notifyInProgressIfNeeded(Stats& stats)
|
||||
{
|
||||
std::chrono::system_clock::time_point now {std::chrono::system_clock::now()};
|
||||
@@ -674,6 +684,8 @@ MediaScanner::scanMediaDirectory(boost::filesystem::path mediaDirectory, bool fo
|
||||
|
||||
itPath.increment(ec);
|
||||
}
|
||||
|
||||
notifyInProgress(stats);
|
||||
}
|
||||
|
||||
// Check if a file exists and is still in a media directory
|
||||
|
||||
@@ -121,6 +121,7 @@ class MediaScanner
|
||||
void checkDuplicatedAudioFiles(Stats& stats);
|
||||
void scanAudioFile(const boost::filesystem::path& file, bool forceScan, Stats& stats);
|
||||
void notifyInProgressIfNeeded(Stats& stats);
|
||||
void notifyInProgress(Stats& stats);
|
||||
|
||||
bool _running {false};
|
||||
Wt::WIOService _ioService;
|
||||
|
||||
@@ -95,6 +95,8 @@ createNetworkFromCacheFile(boost::filesystem::path path)
|
||||
{
|
||||
try
|
||||
{
|
||||
LMS_LOG(SIMILARITY, INFO) << "Reading network from cache...";
|
||||
|
||||
boost::property_tree::ptree root;
|
||||
|
||||
boost::property_tree::read_xml(path.string(), root);
|
||||
@@ -127,7 +129,7 @@ createNetworkFromCacheFile(boost::filesystem::path path)
|
||||
res.setRefVector({x, y}, refVector);
|
||||
}
|
||||
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Successfully read network from cache";
|
||||
LMS_LOG(SIMILARITY, INFO) << "Successfully read network from cache";
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -180,6 +182,8 @@ createObjectPositionsFromCacheFile(boost::filesystem::path path)
|
||||
{
|
||||
try
|
||||
{
|
||||
LMS_LOG(SIMILARITY, INFO) << "Reading object position from cache...";
|
||||
|
||||
boost::property_tree::ptree root;
|
||||
|
||||
boost::property_tree::read_xml(path.string(), root);
|
||||
@@ -198,7 +202,7 @@ createObjectPositionsFromCacheFile(boost::filesystem::path path)
|
||||
}
|
||||
}
|
||||
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Successfully read object position from cache";
|
||||
LMS_LOG(SIMILARITY, INFO) << "Successfully read object position from cache";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ FeaturesScannerAddon::FeaturesScannerAddon(Wt::Dbo::SqlConnectionPool& connectio
|
||||
boost::optional<Similarity::FeaturesCache> cache {Similarity::FeaturesCache::read()};
|
||||
if (cache)
|
||||
{
|
||||
auto searcher {std::make_shared<Similarity::FeaturesSearcher>(_db.getSession(), *cache)};
|
||||
auto searcher {std::make_shared<Similarity::FeaturesSearcher>(_db.getSession(), *cache, [&]() { return _stopRequested; })};
|
||||
if (searcher->isValid())
|
||||
std::atomic_store(&_searcher, searcher);
|
||||
}
|
||||
@@ -107,7 +107,12 @@ FeaturesScannerAddon::preScanComplete()
|
||||
LMS_LOG(DBUPDATER, DEBUG) << "Getting tracks with missing Features DONE (found " << tracksInfo.size() << ")";
|
||||
|
||||
for (const TrackInfo& trackInfo : tracksInfo)
|
||||
{
|
||||
if (_stopRequested)
|
||||
return;
|
||||
|
||||
fetchFeatures(trackInfo.id, trackInfo.mbid);
|
||||
}
|
||||
|
||||
Similarity::FeaturesCache::invalidate();
|
||||
updateSearcher();
|
||||
@@ -116,9 +121,13 @@ FeaturesScannerAddon::preScanComplete()
|
||||
void
|
||||
FeaturesScannerAddon::updateSearcher()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction {_db.getSession()};
|
||||
std::vector<Database::IdType> trackIds {Database::Track::getAllIdsWithFeatures(_db.getSession())};
|
||||
transaction.commit();
|
||||
LMS_LOG(SIMILARITY, INFO) << "Updating searcher...";
|
||||
|
||||
std::vector<Database::IdType> trackIds;
|
||||
{
|
||||
Wt::Dbo::Transaction transaction {_db.getSession()};
|
||||
trackIds = Database::Track::getAllIdsWithFeatures(_db.getSession());
|
||||
}
|
||||
|
||||
if (trackIds.empty())
|
||||
{
|
||||
@@ -127,7 +136,7 @@ FeaturesScannerAddon::updateSearcher()
|
||||
return;
|
||||
}
|
||||
|
||||
auto searcher {std::make_shared<Similarity::FeaturesSearcher>(_db.getSession(), _stopRequested)};
|
||||
auto searcher {std::make_shared<Similarity::FeaturesSearcher>(_db.getSession(), [&]() { return _stopRequested; })};
|
||||
if (searcher->isValid())
|
||||
{
|
||||
std::atomic_store(&_searcher, searcher);
|
||||
@@ -137,8 +146,10 @@ FeaturesScannerAddon::updateSearcher()
|
||||
LMS_LOG(DBUPDATER, INFO) << "New features similarity searcher instanciated";
|
||||
}
|
||||
else
|
||||
{
|
||||
LMS_LOG(DBUPDATER, ERROR) << "Cannot set up a valid features similarity searcher!";
|
||||
std::atomic_store(&_searcher, std::shared_ptr<FeaturesSearcher>{});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -150,7 +161,7 @@ FeaturesScannerAddon::fetchFeatures(Database::IdType trackId, const std::string&
|
||||
std::string data {AcousticBrainz::extractLowLevelFeatures(MBID)};
|
||||
if (data.empty())
|
||||
{
|
||||
LMS_LOG(DBUPDATER, ERROR) << "Cannot extract features using AcousticBrainz!";
|
||||
LMS_LOG(DBUPDATER, ERROR) << "Track " << trackId << ", MBID = '" << MBID << "': cannot extract features using AcousticBrainz";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,8 +119,10 @@ getInputVectorWeights(const FeatureInfoMap& featuresInfo, std::size_t nbDimensio
|
||||
return weights;
|
||||
}
|
||||
|
||||
FeaturesSearcher::FeaturesSearcher(Wt::Dbo::Session& session, bool& stopRequested)
|
||||
FeaturesSearcher::FeaturesSearcher(Wt::Dbo::Session& session, std::function<bool()> stopRequested)
|
||||
{
|
||||
LMS_LOG(SIMILARITY, INFO) << "Constructing features searcher...";
|
||||
|
||||
Wt::Dbo::Transaction transaction {session};
|
||||
|
||||
FeatureInfoMap featuresInfo {getFeatureInfoMap(session)};
|
||||
@@ -143,7 +145,7 @@ FeaturesSearcher::FeaturesSearcher(Wt::Dbo::Session& session, bool& stopRequeste
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Extracting features...";
|
||||
for (Database::IdType trackId : trackIds)
|
||||
{
|
||||
if (stopRequested)
|
||||
if (stopRequested())
|
||||
return;
|
||||
|
||||
boost::optional<SOM::InputVector> inputVector {getInputVectorFromTrack(session, trackId, featuresInfo, nbDimensions)};
|
||||
@@ -181,20 +183,18 @@ FeaturesSearcher::FeaturesSearcher(Wt::Dbo::Session& session, bool& stopRequeste
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Current pass = " << iter.idIteration << " / " << iter.iterationCount;
|
||||
}};
|
||||
|
||||
auto stopper{[&]() { return stopRequested; }};
|
||||
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Training network...";
|
||||
network.train(samples, 10, progressIndicator, stopper);
|
||||
network.train(samples, 10, progressIndicator, stopRequested);
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Training network DONE";
|
||||
|
||||
if (stopRequested)
|
||||
if (stopRequested())
|
||||
return;
|
||||
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Classifying tracks...";
|
||||
std::map<Database::IdType, std::set<SOM::Position>> trackPositions;
|
||||
for (std::size_t i {}; i < samples.size(); ++i)
|
||||
{
|
||||
if (stopRequested)
|
||||
if (stopRequested())
|
||||
return;
|
||||
|
||||
const SOM::Position position {network.getClosestRefVectorPosition(samples[i])};
|
||||
@@ -204,15 +204,18 @@ FeaturesSearcher::FeaturesSearcher(Wt::Dbo::Session& session, bool& stopRequeste
|
||||
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Classifying tracks DONE";
|
||||
|
||||
init(session, std::move(network), std::move(trackPositions));
|
||||
init(session, std::move(network), std::move(trackPositions), stopRequested);
|
||||
|
||||
LMS_LOG(SIMILARITY, INFO) << "Successfully constructed features searcher";
|
||||
}
|
||||
|
||||
FeaturesSearcher::FeaturesSearcher(Wt::Dbo::Session& session, FeaturesCache cache)
|
||||
FeaturesSearcher::FeaturesSearcher(Wt::Dbo::Session& session, FeaturesCache cache, std::function<bool()> stopRequested)
|
||||
{
|
||||
init(session, std::move(cache._network), std::move(cache._trackPositions));
|
||||
LMS_LOG(SIMILARITY, INFO) << "Constructing features searcher from cache...";
|
||||
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Init from cache DONE";
|
||||
init(session, std::move(cache._network), std::move(cache._trackPositions), stopRequested);
|
||||
|
||||
LMS_LOG(SIMILARITY, INFO) << "Successfully constructed features searcher from cache";
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -318,14 +321,15 @@ FeaturesSearcher::toCache() const
|
||||
void
|
||||
FeaturesSearcher::init(Wt::Dbo::Session& session,
|
||||
SOM::Network network,
|
||||
std::map<Database::IdType, std::set<SOM::Position>> tracksPosition)
|
||||
std::map<Database::IdType,
|
||||
std::set<SOM::Position>> tracksPosition,
|
||||
std::function<bool()> stopRequested)
|
||||
{
|
||||
_network = std::make_unique<SOM::Network>(std::move(network));
|
||||
_networkRefVectorsDistanceMedian = _network->computeRefVectorsDistanceMedian();
|
||||
_networkRefVectorsDistanceMedian = network.computeRefVectorsDistanceMedian();
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Median distance betweend ref vectors = " << _networkRefVectorsDistanceMedian;
|
||||
|
||||
SOM::Coordinate width {_network->getWidth()};
|
||||
SOM::Coordinate height {_network->getHeight()};
|
||||
SOM::Coordinate width {network.getWidth()};
|
||||
SOM::Coordinate height {network.getHeight()};
|
||||
|
||||
_artistsMap = SOM::Matrix<std::set<Database::IdType>>{width, height};
|
||||
_releasesMap = SOM::Matrix<std::set<Database::IdType>>{width, height};
|
||||
@@ -335,6 +339,9 @@ FeaturesSearcher::init(Wt::Dbo::Session& session,
|
||||
|
||||
for (auto itTrackCoord : tracksPosition)
|
||||
{
|
||||
if (stopRequested())
|
||||
return;
|
||||
|
||||
Wt::Dbo::Transaction transaction {session};
|
||||
|
||||
Database::IdType trackId {itTrackCoord.first};
|
||||
@@ -362,6 +369,8 @@ FeaturesSearcher::init(Wt::Dbo::Session& session,
|
||||
}
|
||||
}
|
||||
|
||||
_network = std::make_unique<SOM::Network>(std::move(network));
|
||||
|
||||
LMS_LOG(SIMILARITY, DEBUG) << "Constructing maps... DONE";
|
||||
|
||||
}
|
||||
|
||||
@@ -36,10 +36,10 @@ class FeaturesSearcher
|
||||
public:
|
||||
|
||||
// Use cache
|
||||
FeaturesSearcher(Wt::Dbo::Session& session, FeaturesCache cache);
|
||||
FeaturesSearcher(Wt::Dbo::Session& session, FeaturesCache cache, std::function<bool()> stopRequested);
|
||||
|
||||
// Use training (may be very slow)
|
||||
FeaturesSearcher(Wt::Dbo::Session& session, bool& stopRequested);
|
||||
FeaturesSearcher(Wt::Dbo::Session& session, std::function<bool()> stopRequested);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
@@ -61,7 +61,8 @@ class FeaturesSearcher
|
||||
|
||||
void init(Wt::Dbo::Session& session,
|
||||
SOM::Network network,
|
||||
ObjectPositions tracksPosition);
|
||||
ObjectPositions tracksPosition,
|
||||
std::function<bool()> stopRequested);
|
||||
|
||||
std::vector<Database::IdType> getSimilarObjects(const std::set<Database::IdType>& ids,
|
||||
const SOM::Matrix<std::set<Database::IdType>>& objectsMap,
|
||||
|
||||
Reference in New Issue
Block a user