Hey RJ,
I spent some time last night looking into the problem we've both
recently encountered where the library scanner likes to leave the
database in a locked state. If I run Mixxx, cancel a library scan, close
Mixxx, and do that 2 more times, I can get permanently lock our SQLite
DB every time.
Background for onlookers: Beta1 has no database problems that we know of
aside from performance lacking. Trunk has a spiffy caching layer that
minimizes the number of times we actually hit the database, written by
RJ. Somewhere along the way, it looks like we introduced a bug where the
database likes to go into a state where it's permanently locked. (SQLite
uses table-level locking for concurrent access IIRC.)
I've made some small tweaks here but I'm not sure why this has improved
it. I can't seem to permalock the database with this set of code.
(Ignore all the engine changes, I'm still working on fixing crashes and
stuff too.)
The relevant changes are:
- Removed transaction from inside detectMovedFiles() because that
function is called from inside a transaction already.
- Temporarily disable the Analyze view for debugging.
- Try to cleanly cancel a library scan on exit, if it's not already
stopped (I don't really think this code is working the way I thought.)
- In the top level of the library scanner, moved some transaction starts
around because some of the DAO functions we called start their own
transactions.
- The last thing I tried was adding an m_database.rollback() right
before we close the database connections in case there's any outstanding
transactions. This is a giant hack, I was just using it to test if
perhaps the locking problem we have is because we're starting more
transactions than we're finishing.
Because I had to run Mixxx three times to trigger the permalock before,
I suspect that we actually did/do just have some mismatched transaction
stuff going on. I don't think there's any super subtle problem, I just
need to go through this patch and figure out exactly what fixes it.
Just wanted to keep everyone posted on what I'm up to...
Albert
=== modified file 'mixxx/src/engine/enginebuffer.cpp'
--- mixxx/src/engine/enginebuffer.cpp 2010-03-20 21:14:06 +0000
+++ mixxx/src/engine/enginebuffer.cpp 2010-04-15 01:58:29 +0000
@@ -402,6 +402,15 @@
// If the rate has changed, set it in the scale object
if (rate != rate_old || m_bScalerChanged) {
// The rate returned by the scale object can be different from the wanted rate!
+
+ //XXX: Trying to force RAMAN to read from correct
+ // playpos when rate changes direction - Albert
+ if ((rate_old <= 0 && rate > 0) ||
+ (rate_old >= 0 && rate < 0))
+ {
+ setNewPlaypos(filepos_play);
+ }
+
rate_old = rate;
rate = baserate*m_pScale->setTempo(rate/baserate);
m_pScale->setBaseRate(baserate);
=== modified file 'mixxx/src/engine/enginebufferscalelinear.cpp'
--- mixxx/src/engine/enginebufferscalelinear.cpp 2010-01-28 07:43:38 +0000
+++ mixxx/src/engine/enginebufferscalelinear.cpp 2010-04-11 21:47:10 +0000
@@ -131,8 +131,11 @@
samples += (rate_add_abs * ((buf_size - iRateLerpLength)/2));
// Multiply by 2 because it is predicting mono rates, while we want a stereo
// number of samples.
- samples *= 2;
+
+ //samples *= 2; XXX See below -- Albert
+ samples = ceil(samples) * 2;
+ //XXX ALBERT - Do the ceil before the doubling!
unscaled_samples_needed = ceil(samples);
if (!even(unscaled_samples_needed))
unscaled_samples_needed++;
@@ -155,19 +158,26 @@
while(i < buf_size)
{
prev_sample = current_sample;
- //qDebug("EBSL %d %f %f", prev_sample, buffer_index, new_playpos);
current_sample = floor(buffer_index) * 2;
+ //XXX ALBERT Trying this instead:
+ //current_sample = floor(buffer_index*2);
+
+ //This code does nothing in it's current position
+ //because we're multiplying by 2 above -- Albert
if (!even(current_sample))
- current_sample++;
+ current_sample--;
Q_ASSERT(current_sample % 2 == 0);
Q_ASSERT(current_sample >= 0);
+
+ //qDebug("EBSL cur_sample %ld buffer_idx %f new_playpos %f", current_sample, buffer_index, new_playpos);
if (prev_sample != current_sample) {
m_fPreviousL = buffer_int[prev_sample];
m_fPreviousR = buffer_int[prev_sample+1];
}
+ ///XXX ALBERT - This line looks totally bogus. Why +1???
if (current_sample+1 >= buffer_size) {
//Q_ASSERT(unscaled_samples_needed > 0);
if (unscaled_samples_needed == 0) {
@@ -196,6 +206,7 @@
unscaled_samples_needed -= buffer_size;
buffer_index = buffer_index - floor(buffer_index);
+ //XXX ALBERT commented out:
continue;
}
@@ -209,7 +220,7 @@
rate_add = rate_add_new;
}
- CSAMPLE frac = buffer_index - floor(buffer_index);
+ CSAMPLE frac = (buffer_index - floor(buffer_index));
//Perform linear interpolation
buffer[i] = m_fPreviousL + frac * (buffer_int[current_sample] - m_fPreviousL);
@@ -220,7 +231,7 @@
else
buffer_index += rate_add_abs;
- //qDebug("current_sample %d buffer_index %f new_playpos %f", current_sample, buffer_index, new_playpos);
+ //qDebug("current_sample %ld buffer_index %f new_playpos %f frac %f", current_sample, buffer_index, new_playpos, frac);
i+=2;
}
@@ -231,6 +242,7 @@
for (; i < buf_size; i += 2) {
buffer[i] = 0.0f;
buffer[i+1] = 0.0f;
+ qDebug() << "Zeroing samples...";
}
// It's possible that we will exit this function without having satisfied
=== modified file 'mixxx/src/engine/enginebufferscalest.cpp'
--- mixxx/src/engine/enginebufferscalest.cpp 2009-09-22 20:13:30 +0000
+++ mixxx/src/engine/enginebufferscalest.cpp 2010-04-14 07:19:03 +0000
@@ -164,7 +164,6 @@
iCurPos--;
}
-
//If we've just cleared SoundTouch's FIFO of unprocessed samples,
//then reset our "read ahead position" because we probably need
//to read backwards instead of forwards or something like that.
@@ -186,9 +185,12 @@
//long remaining_source_frames = iBaseLength/2;
CSAMPLE* read = buffer;
bool last_read_failed = false;
+ long received_frames = 0;
while (remaining_frames > 0) {
- long received_frames = m_pSoundTouch->receiveSamples((SAMPLETYPE*)read,
+ if (m_pSoundTouch->numSamples() >= remaining_frames) {
+ received_frames = m_pSoundTouch->receiveSamples((SAMPLETYPE*)read,
remaining_frames);
+ }
remaining_frames -= received_frames;
total_received_frames += received_frames;
read += received_frames*2;
@@ -232,18 +234,22 @@
if (total_received_frames != buf_size/2)
{
qDebug() << __FILE__ << "- only wrote" << total_received_frames << "frames instead of requested" << buf_size;
+
+ clear();
}
//for (unsigned long i = 0; i < buf_size; i++)
// qDebug() << buffer[i];
+
if (m_bBackwards)
new_playpos = playpos - m_dTempo*m_dBaseRate*total_received_frames*2;
else
new_playpos = playpos + m_dTempo*m_dBaseRate*total_received_frames*2;
-
+
m_qMutex.unlock();
+
return buffer;
}
=== modified file 'mixxx/src/library/dao/trackdao.cpp'
--- mixxx/src/library/dao/trackdao.cpp 2010-04-03 23:26:07 +0000
+++ mixxx/src/library/dao/trackdao.cpp 2010-04-30 06:00:01 +0000
@@ -534,7 +534,7 @@
void TrackDAO::detectMovedFiles()
{
//qDebug() << "markUnverifiedTracksAsDeleted()";
- m_database.transaction();
+ //m_database.transaction();
QSqlQuery query(m_database);
@@ -598,5 +598,5 @@
}
}
- m_database.commit();
+ //m_database.commit();
}
=== modified file 'mixxx/src/library/library.cpp'
--- mixxx/src/library/library.cpp 2010-04-12 00:32:52 +0000
+++ mixxx/src/library/library.cpp 2010-04-30 03:14:15 +0000
@@ -60,7 +60,8 @@
addFeature(m_pPlaylistFeature);
addFeature(new CrateFeature(this, m_pTrackCollection));
addFeature(new BrowseFeature(this, pConfig, m_pTrackCollection));
- addFeature(new PrepareFeature(this, pConfig, m_pTrackCollection));
+ //addFeature(new PrepareFeature(this, pConfig, m_pTrackCollection));
+
//iTunes and Rhythmbox should be last until we no longer have an obnoxious
//messagebox popup when you select them. (This forces you to reach for your
//mouse or keyboard if you're using MIDI control and you scroll through them...)
=== modified file 'mixxx/src/library/libraryscanner.cpp'
--- mixxx/src/library/libraryscanner.cpp 2010-01-11 05:30:11 +0000
+++ mixxx/src/library/libraryscanner.cpp 2010-04-30 05:50:23 +0000
@@ -43,8 +43,12 @@
// the m_trackDao that lives inside this class. It should use
// the DAOs that live in m_pTrackCollection.
- if (isRunning())
+ if (isRunning()) {
+ //Cancel any running library scan...
+ m_pCollection->slotCancelLibraryScan();
+
wait(); //Wait for thread to finish
+ }
//Do housekeeping on the LibraryHashes table.
m_pCollection->getDatabase().transaction();
@@ -74,14 +78,15 @@
qDebug() << query.lastError();
}
- m_pCollection->getDatabase().commit();
-
QString dir;
foreach(dir, deletedDirs) {
m_pCollection->getTrackDAO().markTrackLocationsAsDeleted(dir);
}
-
+
+ m_pCollection->getDatabase().commit();
+
//Close our database connection
+ m_database.rollback(); //Rollback any uncommitted transaction
m_database.close();
qDebug() << "LibraryScanner destroyed";
@@ -138,16 +143,20 @@
qDebug() << "Recursively scanning library.";
//Start scanning the library.
- m_database.transaction();
+ //THIS SHOULD NOT BE IN A TRANSACTION! Each addTrack() call from inside
+ //recursiveScan() handles it's own transactions.
bool bScanFinishedCleanly = recursiveScan(m_qLibraryPath);
-
if (!bScanFinishedCleanly) {
qDebug() << "Recursive scan interrupted.";
} else {
qDebug() << "Recursive scan finished cleanly.";
}
+ //Start a transaction for all the library hashing (moved file detection)
+ //stuff.
+ m_database.transaction();
+
//At the end of a scan, mark all tracks that weren't "verified" as "deleted"
//(as long as the scan wasn't cancelled half way through. This condition is
//important because our rescanning algorithm starts by marking all tracks as
=== modified file 'mixxx/src/library/trackcollection.cpp'
--- mixxx/src/library/trackcollection.cpp 2010-02-22 03:48:13 +0000
+++ mixxx/src/library/trackcollection.cpp 2010-04-30 05:53:41 +0000
@@ -40,6 +40,7 @@
// Save all tracks that haven't been saved yet.
m_trackDao.saveDirtyTracks();
+ m_db.rollback(); //Rollback any unfinished transactions... testing!
m_db.close();
qDebug() << "TrackCollection destroyed";
}
------------------------------------------------------------------------------
_______________________________________________
Mixxx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixxx-devel