Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions src/analyzer/analyzerqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
#include "analyzer/analyzergain.h"
#include "analyzer/analyzerebur128.h"
#include "analyzer/analyzerwaveform.h"
#include "library/dao/analysisdao.h"
#include "mixer/playerinfo.h"
#include "sources/soundsourceproxy.h"
#include "track/track.h"
#include "util/compatibility.h"
#include "util/db/dbconnectionpooler.h"
#include "util/db/dbconnectionpooled.h"
#include "util/event.h"
#include "util/timer.h"
#include "util/trace.h"
Expand Down Expand Up @@ -51,7 +53,8 @@ AnalyzerQueue::AnalyzerQueue(
m_queue_size(0) {

if (mode != Mode::WithoutWaveform) {
m_pAnalyzers.push_back(std::make_unique<AnalyzerWaveform>(pConfig));
m_pAnalysisDao = std::make_unique<AnalysisDao>(pConfig);
m_pAnalyzers.push_back(std::make_unique<AnalyzerWaveform>(m_pAnalysisDao.get()));
}
m_pAnalyzers.push_back(std::make_unique<AnalyzerGain>(pConfig));
m_pAnalyzers.push_back(std::make_unique<AnalyzerEbur128>(pConfig));
Expand Down Expand Up @@ -197,7 +200,7 @@ bool AnalyzerQueue::doAnalysis(TrackPointer tio, mixxx::AudioSourcePointer pAudi

const SINT framesRead =
pAudioSource->readSampleFramesStereo(
kAnalysisFramesPerBlock,
framesToRead,
&m_sampleBuffer);
DEBUG_ASSERT(framesRead <= framesToRead);
frameIndex += framesRead;
Expand Down Expand Up @@ -299,12 +302,25 @@ void AnalyzerQueue::run() {
}

void AnalyzerQueue::execThread() {
const mixxx::DbConnectionPooler dbConnection(m_pDbConnectionPool);
if (!dbConnection) {
kLogger.warning()
<< "Failed to open database connection for analyzer queue";
kLogger.debug() << "Exiting thread";
return;
// The thread-local database connection for waveform analysis must not
// be closed before returning from this function. Therefore the
// DbConnectionPooler is defined at this outer function scope,
// independent of whether a database connection will be opened
// or not.
mixxx::DbConnectionPooler dbConnectionPooler;
// m_pAnalysisDao remains null if no analyzer needs database access.
// Currently only waveform analyses makes use of it.
if (m_pAnalysisDao) {
dbConnectionPooler = mixxx::DbConnectionPooler(m_pDbConnectionPool); // move assignment
if (!dbConnectionPooler.isPooling()) {
kLogger.warning()
<< "Failed to obtain database connection for analyzer queue thread";
return;
}
// Obtain and use the newly created database connection within this thread
QSqlDatabase dbConnection = mixxx::DbConnectionPooled(m_pDbConnectionPool);
DEBUG_ASSERT(dbConnection.isOpen());
m_pAnalysisDao->initialize(dbConnection);
}

m_progressInfo.current_track.reset();
Expand Down Expand Up @@ -380,6 +396,13 @@ void AnalyzerQueue::execThread() {
}
emptyCheck();
}

if (m_pAnalysisDao) {
// Invalidate reference to the thread-local database connection
// that will be closed soon. Not necessary, just in case ;)
m_pAnalysisDao->initialize(QSqlDatabase());
}

emit(queueEmpty()); // emit in case of exit;
}

Expand Down
3 changes: 3 additions & 0 deletions src/analyzer/analyzerqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "util/memory.h"

class Analyzer;
class AnalysisDao;

class AnalyzerQueue : public QThread {
Q_OBJECT
Expand Down Expand Up @@ -60,6 +61,8 @@ class AnalyzerQueue : public QThread {

mixxx::DbConnectionPoolPtr m_pDbConnectionPool;

std::unique_ptr<AnalysisDao> m_pAnalysisDao;

typedef std::unique_ptr<Analyzer> AnalyzerPtr;
std::vector<AnalyzerPtr> m_pAnalyzers;

Expand Down
13 changes: 7 additions & 6 deletions src/analyzer/analyzerwaveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ mixxx::Logger kLogger("AnalyzerWaveform");
} // anonymous

AnalyzerWaveform::AnalyzerWaveform(
const UserSettingsPointer& pConfig) :
m_analysisDao(pConfig),
AnalysisDao* pAnalysisDao) :
m_pAnalysisDao(pAnalysisDao),
m_skipProcessing(false),
m_waveformData(nullptr),
m_waveformSummaryData(nullptr),
m_stride(0, 0),
m_currentStride(0),
m_currentSummaryStride(0) {
DEBUG_ASSERT(m_pAnalysisDao); // mandatory
m_filter[0] = 0;
m_filter[1] = 0;
m_filter[2] = 0;
Expand Down Expand Up @@ -102,7 +103,7 @@ bool AnalyzerWaveform::isDisabledOrLoadStoredSuccess(TrackPointer tio) const {

if (trackId.isValid() && (missingWaveform || missingWavesummary)) {
QList<AnalysisDao::AnalysisInfo> analyses =
m_analysisDao.getAnalysesForTrack(trackId);
m_pAnalysisDao->getAnalysesForTrack(trackId);

QListIterator<AnalysisDao::AnalysisInfo> it(analyses);
while (it.hasNext()) {
Expand All @@ -117,7 +118,7 @@ bool AnalyzerWaveform::isDisabledOrLoadStoredSuccess(TrackPointer tio) const {
missingWaveform = false;
} else if (vc != WaveformFactory::VC_KEEP) {
// remove all other Analysis except that one we should keep
m_analysisDao.deleteAnalysis(analysis.analysisId);
m_pAnalysisDao->deleteAnalysis(analysis.analysisId);
}
} if (analysis.type == AnalysisDao::TYPE_WAVESUMMARY) {
vc = WaveformFactory::waveformSummaryVersionToVersionClass(analysis.version);
Expand All @@ -127,7 +128,7 @@ bool AnalyzerWaveform::isDisabledOrLoadStoredSuccess(TrackPointer tio) const {
missingWavesummary = false;
} else if (vc != WaveformFactory::VC_KEEP) {
// remove all other Analysis except that one we should keep
m_analysisDao.deleteAnalysis(analysis.analysisId);
m_pAnalysisDao->deleteAnalysis(analysis.analysisId);
}
}
}
Expand Down Expand Up @@ -309,7 +310,7 @@ void AnalyzerWaveform::finalize(TrackPointer tio) {
// waveforms (i.e. if the config setting was disabled in a previous scan)
// and then it is not called. The other analyzers have signals which control
// the update of their data.
m_analysisDao.saveTrackAnalyses(*tio);
m_pAnalysisDao->saveTrackAnalyses(*tio);

kLogger.debug() << "Waveform generation for track" << tio->getId() << "done"
<< m_timer.elapsed().debugSecondsWithUnit();
Expand Down
6 changes: 3 additions & 3 deletions src/analyzer/analyzerwaveform.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

#include "analyzer/analyzer.h"
#include "waveform/waveform.h"
#include "library/dao/analysisdao.h"
#include "util/math.h"
#include "util/performancetimer.h"

//NOTS vrince some test to segment sound, to apply color in the waveform
//#define TEST_HEAT_MAP

class EngineFilterIIRBase;
class AnalysisDao;

inline CSAMPLE scaleSignal(CSAMPLE invalue, FilterIndex index = FilterCount) {
if (invalue == 0.0) {
Expand Down Expand Up @@ -137,7 +137,7 @@ struct WaveformStride {
class AnalyzerWaveform : public Analyzer {
public:
explicit AnalyzerWaveform(
const UserSettingsPointer& pConfig);
AnalysisDao* pAnalysisDao);
~AnalyzerWaveform() override;

bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
Expand All @@ -154,7 +154,7 @@ class AnalyzerWaveform : public Analyzer {
void destroyFilters();
void storeIfGreater(float* pDest, float source);

mutable AnalysisDao m_analysisDao;
AnalysisDao* m_pAnalysisDao;

bool m_skipProcessing;

Expand Down
2 changes: 1 addition & 1 deletion src/preferences/upgrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ UserSettingsPointer Upgrade::versionUpgrade(const QString& settingsPath) {
MixxxDb mixxxDb(config);
const mixxx::DbConnectionPooler dbConnectionPooler(
mixxxDb.connectionPool());
if (dbConnectionPooler) {
if (dbConnectionPooler.isPooling()) {
QSqlDatabase dbConnection = mixxx::DbConnectionPooled(mixxxDb.connectionPool());
DEBUG_ASSERT(dbConnection.isOpen());
if (MixxxDb::initDatabaseSchema(dbConnection)) {
Expand Down
4 changes: 3 additions & 1 deletion src/test/analyserwaveformtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ namespace {
class AnalyzerWaveformTest: public MixxxTest {
protected:
AnalyzerWaveformTest()
: aw(config()),
: analysisDao(config()),
aw(&analysisDao),
bigbuf(nullptr),
canaryBigBuf(nullptr) {
}
Expand Down Expand Up @@ -49,6 +50,7 @@ class AnalyzerWaveformTest: public MixxxTest {
}

protected:
AnalysisDao analysisDao;
AnalyzerWaveform aw;
TrackPointer tio;
CSAMPLE* bigbuf;
Expand Down
37 changes: 37 additions & 0 deletions src/test/dbconnectionpool_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <gtest/gtest.h>

#include "test/mixxxtest.h"

#include "database/mixxxdb.h"
#include "util/db/dbconnectionpooler.h"
#include "util/db/dbconnectionpooled.h"

#include "library/dao/settingsdao.h"

#include "util/assert.h"


class DbConnectionPoolTest : public MixxxTest {
protected:
DbConnectionPoolTest()
: m_mixxxDb(config()) {
}

protected:
const MixxxDb m_mixxxDb;
};

TEST_F(DbConnectionPoolTest, MoveSemantics) {
mixxx::DbConnectionPooler p1(m_mixxxDb.connectionPool());
EXPECT_TRUE(p1.isPooling());

// Move construction
mixxx::DbConnectionPooler p2(std::move(p1));
EXPECT_FALSE(p1.isPooling());
EXPECT_TRUE(p2.isPooling());

// Move assignment
p1 = std::move(p2);
EXPECT_TRUE(p1.isPooling());
EXPECT_FALSE(p2.isPooling());
}
3 changes: 2 additions & 1 deletion src/util/db/dbconnectionpooler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ DbConnectionPooler::DbConnectionPooler(
DbConnectionPoolPtr pDbConnectionPool) {
if (pDbConnectionPool && pDbConnectionPool->createThreadLocalConnection()) {
// m_pDbConnectionPool indicates if the thread-local connection has actually
// been created during construction. Otherwise this instance is non-functional.
// been created during construction. Otherwise this instance does not store
// any reference to the connection pool and is non-functional.
m_pDbConnectionPool = std::move(pDbConnectionPool);
}
}
Expand Down
29 changes: 21 additions & 8 deletions src/util/db/dbconnectionpooler.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,35 @@ class DbConnectionPooler final {
public:
explicit DbConnectionPooler(
DbConnectionPoolPtr pDbConnectionPool = DbConnectionPoolPtr());
DbConnectionPooler(
DbConnectionPooler&& other) = default;
DbConnectionPooler(const DbConnectionPooler&) = delete;
#if !defined(_MSC_VER) || _MSC_VER > 1900
DbConnectionPooler(DbConnectionPooler&&) = default;
#else
// Workaround for Visual Studio 2015 (and before)
DbConnectionPooler(DbConnectionPooler&& other)
: m_pDbConnectionPool(std::move(other.m_pDbConnectionPool)) {
}
#endif
~DbConnectionPooler();

// Checks if a thread-local connection has actually been created
// during construction. Otherwise this instance does not store
// any reference to the connection pool and is non-functional.
explicit operator bool() const {
// during construction and is owned by this instance.
bool isPooling() const {
return static_cast<bool>(m_pDbConnectionPool);
}

private:
DbConnectionPooler(const DbConnectionPooler&) = delete;
DbConnectionPooler& operator=(const DbConnectionPooler&) = delete;
DbConnectionPooler& operator=(DbConnectionPooler&&) = delete;
#if !defined(_MSC_VER) || _MSC_VER > 1900
DbConnectionPooler& operator=(DbConnectionPooler&&) = default;
#else
// Workaround for Visual Studio 2015 (and before)
DbConnectionPooler& operator=(DbConnectionPooler&& other) {
m_pDbConnectionPool = std::move(other.m_pDbConnectionPool);
return *this;
}
#endif

private:
// Prevent heap allocation
static void * operator new(std::size_t);
static void * operator new[](std::size_t);
Expand Down