[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    KDE/kdepim/akonadi/resources/mbox/libmbox
From:       Bertjan Broeksema <b.broeksema () home ! nl>
Date:       2009-06-26 14:40:09
Message-ID: 1246027209.659420.16654.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 987701 by bbroeksema:

- Greatly simplify the purge method.
- Add some tests for the purge methods. (I consider it reasonably save now).


 M  +45 -58    mbox.cpp  
 M  +59 -0     tests/mboxtest.cpp  
 M  +1 -0      tests/mboxtest.h  


--- trunk/KDE/kdepim/akonadi/resources/mbox/libmbox/mbox.cpp #987700:987701
@@ -337,90 +337,77 @@
     QRegExp regexp( sMBoxSeperatorRegExp );
 
     if ( regexp.indexIn(line) < 0 ) {
+      qDebug() << "Found invalid seperator at:" << offset;
       unlock();
       return false; // The file is messed up or the index is incorrect.
     }
   }
 
+  // All entries are deleted, so just resize the file to a size of 0.
+  if ( deletedItems.size() == d->mEntries.size() ) {
+    d->mEntries.clear();
+    d->mMboxFile.resize( 0 );
+    kDebug() << "Purge comleted successfully, unlocking the file.";
+    return unlock();
+  }
+
   qSort( d->mEntries.begin(), d->mEntries.end(), lessThanByOffset );
   quint64 writeOffset = 0;
+  bool writeOffSetInitialized = false;
   QList<MsgInfo> resultingEntryList;
 
+  quint64 origFileSize = d->mMboxFile.size();
+
   QListIterator<MsgInfo> i( d->mEntries );
   while ( i.hasNext() ) {
     MsgInfo entry = i.next();
 
-    if ( deletedItems.contains( entry.first ) ) {
-      // This entry must get removed from the file.
+    if ( deletedItems.contains( entry.first ) && !writeOffSetInitialized ) {
       writeOffset = entry.first;
-
+      writeOffSetInitialized = true;
+    } else if ( writeOffset < entry.first && !deletedItems.contains( entry.first ) ) {
+      // The current message doesn't have to be deleted, but must be moved.
+      // First determine the size of the entry that must be moved.
+      quint64 entrySize = 0;
       if ( i.hasNext() ) {
-        // One ore more entries after this one, find the first that should be
-        // kept, or find eof if all following entries must be deleted.
-        MsgInfo entryToWrite;
-        bool nextEntryFound = false;
-        while ( i.hasNext() && !nextEntryFound ) {
-          entryToWrite = i.next();
-          if ( !deletedItems.contains( entryToWrite.first ) )
-            nextEntryFound = true;
-        }
+        entrySize = i.next().first - entry.first - 1;
+        i.previous(); // Go back to make sure that we also handle the next entry.
+      } else {
+        entrySize = origFileSize - entry.first - 1;
+      }
 
-        if ( nextEntryFound ) {
-          if ( i.hasNext() ) { // Read the next entry to determine the size.
-            MsgInfo entryAfterEntryToWrite = i.next();
-            quint64 entryToWriteSize = entryAfterEntryToWrite.first - entryToWrite.first - 1;
-            quint64 mapSize = entryAfterEntryToWrite.first - writeOffset - 1;
+      Q_ASSERT( entrySize > 0 ); // MBox entries really cannot have a size <= 0;
 
-            // Now map writeOffSet to entryAfterEntryToWrite offset into mem.
-            uchar *memArea = d->mMboxFile.map( writeOffset, mapSize );
+      // we map the whole area of the file starting at the writeOffset up to the
+      // message that have to be moved into memory. This includes eventually the
+      // messages that are the deleted between the first deleted message
+      // encountered and the message that has to be moved.
+      quint64 mapSize = entry.first + entrySize - writeOffset;
 
-            // Now read the entry that must be moved to writeOffset.
-            quint64 startOffset = entryToWrite.first - writeOffset;
-            char *start = reinterpret_cast<char*>( memArea + startOffset );
-            QByteArray entryToWriteData( start, entryToWriteSize );
+      // Now map writeOffSet + mapSize into mem.
+      uchar *memArea = d->mMboxFile.map( writeOffset, mapSize );
 
-            memcpy( memArea, entryToWriteData.constData(), entryToWriteSize );
+      // Now read the entry that must be moved to writeOffset.
+      quint64 startOffset = entry.first - writeOffset;
+      char *start = reinterpret_cast<char*>( memArea + startOffset );
+      QByteArray entryToWriteData( start, entrySize );
 
-            d->mMboxFile.unmap( memArea );
+      memcpy( memArea, entryToWriteData.constData(), entrySize );
 
-            resultingEntryList << MsgInfo( writeOffset, entryToWrite.second );
-            writeOffset += entryToWriteSize + 1;
-          } else { // entryToWrite is the last entry in the file
-            quint64 entryToWriteSize = d->mMboxFile.size() - entryToWrite.first - 1;
-            quint64 mapSize = d->mMboxFile.size() - writeOffset - 1;
+      d->mMboxFile.unmap( memArea );
 
-            // Now map writeOffSet upto mapSize into mem.
-            uchar *memArea = d->mMboxFile.map( writeOffset, mapSize );
-
-            quint64 startOffset = entryToWrite.first - writeOffset;
-            char *start = reinterpret_cast<char*>( memArea + startOffset );
-            QByteArray entryToWriteData( start, entryToWriteSize );
-
-            memcpy( memArea, entryToWriteData.constData(), entryToWriteSize );
-
-            d->mMboxFile.unmap( memArea );
-
-            resultingEntryList << MsgInfo( writeOffset, entryToWrite.second );
-            writeOffset += entryToWriteSize + 1;
-
-            // Chop off the remaining bytes.
-            d->mMboxFile.resize( writeOffset );
-          }
-        } else {
-          // All entries after writeOffset are marked as deleted so resize the
-          // file.
-          d->mMboxFile.resize( writeOffset );
-        }
-      } else {
-        // It is the last entry of the file so just chop off the remaining content
-        // from writeOffset to end of file.
-        d->mMboxFile.resize( writeOffset );
-      }
-    } else {
       resultingEntryList << MsgInfo( writeOffset, entry.second );
+      writeOffset += entrySize + 1;
+    } else if ( !deletedItems.contains( entry.first ) ) {
+      // Unmoved and not deleted entry, can only occure before the first deleted
+      // entry.
+      Q_ASSERT( !writeOffSetInitialized );
+      resultingEntryList << entry;
     }
   }
 
+  // Chop off remaining entry bits.
+  d->mMboxFile.resize( writeOffset );
   d->mEntries = resultingEntryList;
 
   kDebug() << "Purge comleted successfully, unlocking the file.";
--- trunk/KDE/kdepim/akonadi/resources/mbox/libmbox/tests/mboxtest.cpp #987700:987701
@@ -289,6 +289,65 @@
   QCOMPARE( infos2.at( 2 ).first, infos.at( 2 ).first );
 }
 
+void MboxTest::testPurge()
+{
+  MBox mbox1;
+  QVERIFY( mbox1.setLockType( MBox::None ) );
+  QVERIFY( mbox1.load( fileName() ) );
+  mbox1.appendEntry( mMail1 );
+  mbox1.appendEntry( mMail1 );
+  mbox1.appendEntry( mMail1 );
+  QVERIFY( mbox1.save() );
+
+  QList<MsgInfo> list = mbox1.entryList();
+
+  // First test: Delete only the first (all messages afterwards have to be moved).
+  mbox1.purge( QSet<quint64>() << list.first().first );
+
+  MBox mbox2;
+  QVERIFY( mbox2.load( fileName() ) );
+  QList<MsgInfo> list2 = mbox2.entryList();
+  QCOMPARE( list2.size(), 2 ); // Is a message actually gone?
+
+  quint64 newOffsetSecondMessage = list.last().first - list.at( 1 ).first;
+
+  QCOMPARE( list2.first().first, static_cast<quint64>( 0 ) );
+  QCOMPARE( list2.last().first, newOffsetSecondMessage );
+
+  // Second test: Delete the first two (the last message have to be moved).
+  removeTestFile();
+
+  QVERIFY( mbox1.load( fileName() ) );
+  mbox1.appendEntry( mMail1 );
+  mbox1.appendEntry( mMail1 );
+  mbox1.appendEntry( mMail1 );
+  QVERIFY( mbox1.save() );
+
+  list = mbox1.entryList();
+
+  mbox1.purge( QSet<quint64>() << list.at( 0 ).first << list.at( 1 ).first );
+  QVERIFY( mbox2.load( fileName() ) );
+  list2 = mbox2.entryList();
+  QCOMPARE( list2.size(), 1 ); // Are the messages actually gone?
+  QCOMPARE( list2.first().first, static_cast<quint64>( 0 ) );
+
+  // Third test: Delete all messages.
+  removeTestFile();
+
+  QVERIFY( mbox1.load( fileName() ) );
+  mbox1.appendEntry( mMail1 );
+  mbox1.appendEntry( mMail1 );
+  mbox1.appendEntry( mMail1 );
+  QVERIFY( mbox1.save() );
+
+  list = mbox1.entryList();
+
+  mbox1.purge( QSet<quint64>() << list.at( 0 ).first << list.at( 1 ).first << list.at( 2 ).first );
+  QVERIFY( mbox2.load( fileName() ) );
+  list2 = mbox2.entryList();
+  QCOMPARE( list2.size(), 0 ); // Are the messages actually gone?
+}
+
 void MboxTest::cleanupTestCase()
 {
   mTempDir->unlink();
--- trunk/KDE/kdepim/akonadi/resources/mbox/libmbox/tests/mboxtest.h #987700:987701
@@ -39,6 +39,7 @@
     void testBlankLines();
     void cleanupTestCase();
     void testEntries();
+    void testPurge();
 
   private:
     QString fileName();

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic