diff --git a/src/common/PatchDB.cpp b/src/common/PatchDB.cpp index 7146f858089..316b6083c99 100644 --- a/src/common/PatchDB.cpp +++ b/src/common/PatchDB.cpp @@ -201,7 +201,7 @@ struct TxnGuard struct PatchDB::WriterWorker { - static constexpr const char *schema_version = "9"; // I will rebuild if this is not my verion + static constexpr const char *schema_version = "10"; // I will rebuild if this is not my verion /* * Obviously a lot of thought needs to go into this @@ -320,11 +320,10 @@ CREATE TABLE IF NOT EXISTS Favorites ( void openDb() { - std::cout << "--OPEN" << std::endl; + std::cout << ">>> Opening r/w DB" << std::endl; auto flag = SQLITE_OPEN_NOMUTEX; // basically lock flag |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; - std::cout << "\nPatchDB : Opening sqlitedb " << dbname << std::endl; auto ec = sqlite3_open_v2(dbname.c_str(), &dbh, flag, nullptr); if (ec != SQLITE_OK) @@ -340,7 +339,7 @@ CREATE TABLE IF NOT EXISTS Favorites ( void closeDb() { - std::cout << "--CLOSE" << std::endl; + std::cout << "<<<< Closing r/w DB" << std::endl; if (dbh) sqlite3_close(dbh); dbh = nullptr; @@ -361,8 +360,11 @@ CREATE TABLE IF NOT EXISTS Favorites ( void go(WriterWorker &w) { w.setupDatabase(); } }; + std::atomic hasSetup{false}; void setupDatabase() { + std::cout << "PatchDB : Setup Database " << dbname << std::endl; + hasSetup = true; /* * OK check my version */ @@ -424,9 +426,16 @@ CREATE TABLE IF NOT EXISTS Favorites ( return; // We know this is called in the lock so can manipulate pathQ properly haveOpenedForWriteOnce = true; - std::cout << "CREATING THREAD " << std::endl; qThread = std::thread([this]() { this->loadQueueFunction(); }); - pathQ.push_back(new EnQSetup()); + + { + std::lock_guard g(qLock); + pathQ.push_back(new EnQSetup()); + } + qCV.notify_all(); + while (!hasSetup) + { + } } ~WriterWorker() @@ -899,7 +908,6 @@ CREATE TABLE IF NOT EXISTS Favorites ( { { std::lock_guard g(qLock); - openForWrite(); pathQ.push_back(p); } @@ -913,6 +921,7 @@ CREATE TABLE IF NOT EXISTS Favorites ( auto flag = SQLITE_OPEN_NOMUTEX; // basically lock flag |= SQLITE_OPEN_READONLY; + std::cout << ">>>RO> Opening r/o DB" << std::endl; auto ec = sqlite3_open_v2(dbname.c_str(), &rodbh, flag, nullptr); if (ec != SQLITE_OK) @@ -940,6 +949,7 @@ PatchDB::PatchDB(SurgeStorage *s) : storage(s) { initialize(); } PatchDB::~PatchDB() = default; void PatchDB::initialize() { worker = std::make_unique(storage); } +void PatchDB::prepareForWrites() { worker->openForWrite(); } void PatchDB::considerFXPForLoad(const fs::path &fxp, const std::string &name, const std::string &catName, const CatType type) const @@ -1066,7 +1076,14 @@ std::vector PatchDB::rawQueryForNameLike(const std::string } catch (SQL::Exception &e) { - storage->reportError(e.what(), "PatchDB - rawQueryForNameLike"); + if (e.rc == SQLITE_BUSY) + { + // Oh well + } + else + { + storage->reportError(e.what(), "PatchDB - rawQueryForNameLike"); + } } return res; @@ -1134,8 +1151,9 @@ std::vector PatchDB::internalCategories(int t, const std::st return res; } -void PatchDB::isUserFavorite(const std::string &path, bool isIt) +void PatchDB::setUserFavorite(const std::string &path, bool isIt) { + prepareForWrites(); worker->enqueueWorkItem(new WriterWorker::EnQFavorite(path, isIt)); } std::vector PatchDB::readUserFavorites() @@ -1146,6 +1164,18 @@ std::vector PatchDB::readUserFavorites() try { auto res = std::vector(); + auto hasFav = SQL::Statement( + conn, "SELECT count(*) from sqlite_master where tbl_name = \"Favorites\""); + int favCt = 0; + while (hasFav.step()) + { + favCt = hasFav.col_int(0); + } + hasFav.finalize(); + + if (favCt == 0) + return std::vector(); + auto st = SQL::Statement(conn, "select path from Favorites;"); while (st.step()) { @@ -1156,10 +1186,17 @@ std::vector PatchDB::readUserFavorites() } catch (SQL::Exception &e) { + // This error really doesn't matter most of the time storage->reportError(e.what(), "PatchDB - Loading Favorites"); } return std::vector(); } +int PatchDB::numberOfJobsOutstanding() +{ + std::lock_guard guard(worker->qLock); + return worker->pathQ.size(); +} + } // namespace PatchStorage } // namespace Surge diff --git a/src/common/PatchDB.h b/src/common/PatchDB.h index 2d9d9573f7d..70d2f0593d7 100644 --- a/src/common/PatchDB.h +++ b/src/common/PatchDB.h @@ -67,6 +67,7 @@ struct PatchDB ~PatchDB(); void initialize(); + void prepareForWrites(); SurgeStorage *storage; @@ -78,8 +79,9 @@ struct PatchDB void addRootCategory(const std::string &name, CatType type); void addSubCategory(const std::string &name, const std::string &parent, CatType type); void addDebugMessage(const std::string &debug); + void setUserFavorite(const std::string &path, bool isIt); - void isUserFavorite(const std::string &path, bool isIt); + int numberOfJobsOutstanding(); // Query APIs std::vector> readAllFeatures(); diff --git a/src/common/SurgeStorage.cpp b/src/common/SurgeStorage.cpp index d555784b342..d14df0e5710 100644 --- a/src/common/SurgeStorage.cpp +++ b/src/common/SurgeStorage.cpp @@ -716,6 +716,7 @@ void SurgeStorage::initializePatchDb() return; patchDBInitialized = true; + patchDB->prepareForWrites(); auto catToType = [this](int q) { auto t = Surge::PatchStorage::PatchDB::CatType::FACTORY; diff --git a/src/surge-xt/gui/SurgeGUIEditor.cpp b/src/surge-xt/gui/SurgeGUIEditor.cpp index d786530b793..8d284019801 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.cpp +++ b/src/surge-xt/gui/SurgeGUIEditor.cpp @@ -5398,7 +5398,7 @@ void SurgeGUIEditor::setPatchAsFavorite(bool b) if (synth->patchid >= 0 && synth->patchid < synth->storage.patch_list.size()) { synth->storage.patch_list[synth->patchid].isFavorite = b; - synth->storage.patchDB->isUserFavorite( + synth->storage.patchDB->setUserFavorite( synth->storage.patch_list[synth->patchid].path.u8string(), b); } } diff --git a/src/surge-xt/gui/overlays/PatchDBViewer.cpp b/src/surge-xt/gui/overlays/PatchDBViewer.cpp index 6af400726dd..0da3a14bb5a 100644 --- a/src/surge-xt/gui/overlays/PatchDBViewer.cpp +++ b/src/surge-xt/gui/overlays/PatchDBViewer.cpp @@ -17,6 +17,7 @@ #include "PatchDB.h" #include "SurgeGUIEditor.h" #include "RuntimeFont.h" +#include "fmt/core.h" namespace Surge { @@ -342,7 +343,14 @@ PatchDBViewer::PatchDBViewer(SurgeGUIEditor *e, SurgeStorage *s) storage->initializePatchDb(); createElements(); } -PatchDBViewer::~PatchDBViewer() { treeView->setRootItem(nullptr); }; +PatchDBViewer::~PatchDBViewer() +{ + treeView->setRootItem(nullptr); + if (countdownClock) + { + countdownClock->stopTimer(); + } +}; void PatchDBViewer::createElements() { @@ -383,9 +391,61 @@ void PatchDBViewer::createElements() filters = std::make_unique(); addAndMakeVisible(*filters); - executeQuery(); + jobCountdown = std::make_unique(); + jobCountdown->setText("COUNTDOWN", juce::NotificationType::dontSendNotification); + jobCountdown->setColour(juce::Label::backgroundColourId, + juce::Colour(0xFF, 0x90, 0).withAlpha(0.4f)); + jobCountdown->setJustificationType(juce::Justification::centred); + jobCountdown->setFont(Surge::GUI::getFontManager()->getFiraMonoAtSize(36)); + addChildComponent(*jobCountdown); + + if (storage->patchDB->numberOfJobsOutstanding() > 0) + { + checkJobsOverlay(); + } + else + { + executeQuery(); + } } +struct CountdownTimer : public juce::Timer +{ + CountdownTimer(PatchDBViewer *d) : v(d) {} + PatchDBViewer *v{nullptr}; + void timerCallback() override + { + if (v) + v->checkJobsOverlay(); + } +}; +void PatchDBViewer::checkJobsOverlay() +{ + auto jo = storage->patchDB->numberOfJobsOutstanding(); + if (jo == 0) + { + jobCountdown->setVisible(false); + executeQuery(); + if (countdownClock) + { + countdownClock->stopTimer(); + } + } + else + { + jobCountdown->setText(fmt::format("Jobs Outstanding : {:d}", jo), + juce::NotificationType::dontSendNotification); + jobCountdown->setVisible(true); + if (!countdownClock) + { + countdownClock = std::make_unique(this); + } + if (!countdownClock->isTimerRunning()) + { + countdownClock->startTimerHz(30); + } + } +} void PatchDBViewer::executeQuery() { tableModel->executeQuery(nameTypein->getText().toStdString()); @@ -396,6 +456,9 @@ void PatchDBViewer::textEditorTextChanged(juce::TextEditor &editor) { executeQue void PatchDBViewer::paint(juce::Graphics &g) { g.fillAll(juce::Colours::black); } void PatchDBViewer::resized() { + if (jobCountdown) + jobCountdown->setBounds(getLocalBounds()); + if (nameTypein) nameTypein->setBounds(10, 10, 400, 30); diff --git a/src/surge-xt/gui/overlays/PatchDBViewer.h b/src/surge-xt/gui/overlays/PatchDBViewer.h index b8b77d989f9..92361cf1555 100644 --- a/src/surge-xt/gui/overlays/PatchDBViewer.h +++ b/src/surge-xt/gui/overlays/PatchDBViewer.h @@ -40,6 +40,7 @@ class PatchDBViewer : public OverlayComponent, ~PatchDBViewer(); void createElements(); void executeQuery(); + void checkJobsOverlay(); void paint(juce::Graphics &g) override; @@ -60,6 +61,9 @@ class PatchDBViewer : public OverlayComponent, std::unique_ptr doDebug; void buttonClicked(juce::Button *button) override; + std::unique_ptr jobCountdown; + std::unique_ptr countdownClock; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PatchDBViewer); };