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

Reply via email to