Update the post insert behaviour of the RtcomEventLogger backend to update storage...
[qwerkisync] / DBBackends / RtcomEventLogger.cpp
index aac4790..0766fa2 100644 (file)
@@ -54,7 +54,7 @@ QDebug operator<<(QDebug, GList &);
 QDebug operator<<(QDebug, QList<RTComElAttachment*> &);
 
 RtcomEventLogger::RtcomEventLogger(const Settings &settings) :
-       m_Settings(settings), mk_DBPath("/.rtcom-eventlogger/el-v1.db")
+       m_Settings(settings)
 {
        RTComEl *el(rtcom_el_new());
        if(NULL != el)
@@ -77,7 +77,7 @@ RtcomEventLogger::RtcomEventLogger(const Settings &settings) :
 }
 
 RtcomEventLogger::RtcomEventLogger(const Settings &settings, const EventTypes::RtcomEvent &event) :
-       m_Settings(settings), mk_DBPath("/.rtcom-eventlogger/el-v1.db")
+       m_Settings(settings)
 {
 }
 
@@ -276,13 +276,13 @@ void RtcomEventLogger::Insert(EventTypes::iEvent &event, const NumberToNameLooku
                        // Add the event
                        QDateTime startTime(QDateTime::currentDateTimeUtc());
                        int newEventID(-1);
+                       int currentBackoffInMillisecs(5);
                        while(((newEventID = rtcom_el_add_event_full(el, revent, rheaders, rattachments, &error)) == -1)
-                                 && startTime.msecsTo(QDateTime::currentDateTimeUtc()) < 1000)
+                                 && startTime.msecsTo(QDateTime::currentDateTimeUtc()) < 10000)
                        {
                                if(error != NULL)
                                {
                                        qDebug() << "err: " << error->message;
-                                       qDebug() << *revent << "\n";
                                        g_error_free(error);
                                        error = NULL;
                                }
@@ -292,18 +292,24 @@ void RtcomEventLogger::Insert(EventTypes::iEvent &event, const NumberToNameLooku
                                mutex.lock();
 
                                QWaitCondition waitCondition;
-                               waitCondition.wait(&mutex, 5);
+                               waitCondition.wait(&mutex, currentBackoffInMillisecs);
 
                                mutex.unlock();
+
+                               // Exponential backoff...
+                               currentBackoffInMillisecs *= 2;
                        }
 
                        if(-1 == newEventID)
                        {
+                               qDebug() << "Unable to insert event due to error.";
+                               qDebug() << *revent << "\n";
+                       }
+                       else
+                       {
                                qDebug() << "new id: " << newEventID;
                                InsertedIDs().append(newEventID);
                        }
-                       else
-                               qDebug() << "Unable to insert event due to error.";
 
                        // Release the attachments
                        g_list_foreach (rattachments, (GFunc) rtcom_el_free_attachment, NULL);
@@ -323,6 +329,10 @@ void RtcomEventLogger::Insert(EventTypes::iEvent &event, const NumberToNameLooku
 
 void RtcomEventLogger::PostInsert()
 {
+       // Our new events get the specified storage times ignored, and some things
+       // use these, so bodge them for now.
+       UpdateInsertedStorageTimes();
+
        // Reorder the DB IDs as Nokia are guilty of both premature
        // optimisation as well as closed source UIs...
        Reindex();
@@ -335,19 +345,59 @@ void RtcomEventLogger::ClearInsertedIDs()
        InsertedIDs().clear();
 }
 
-// Reorder the DB IDs as Nokia are guilty of both premature
-// optimisation as well as closed source UIs...
-void RtcomEventLogger::Reindex()
+void RtcomEventLogger::UpdateInsertedStorageTimes()
 {
        // Set up the database connection...
-       QSqlDatabase db(QSqlDatabase::addDatabase( "QSQLITE" ));
+       QSqlDatabase db(QSqlDatabase::addDatabase("QSQLITE"));
 
-       db.setDatabaseName( QDir::homePath() + mk_DBPath );
-       if ( ! db.open() )
+       db.setDatabaseName(CurrentSettings().DBPath());
+       if(db.open())
        {
-               throw std::runtime_error("Cannot open database: Unable to establish database connection");
+               // Update storage time as some software uses it...
+               QSqlQuery * updateStorageTimeQuery(new QSqlQuery(db));
+               if(updateStorageTimeQuery != NULL)
+               {
+                       updateStorageTimeQuery->setForwardOnly( true );
+
+                       if(db.transaction())
+                       {
+                               try
+                               {
+                                       QString sqlUpdateStorageTime(QString("UPDATE events SET storage_time = start_time WHERE id IN (%1)")
+                                               .arg(IntsToStringList(InsertedIDs()).join(",")));
+                                       if (!updateStorageTimeQuery->exec(sqlUpdateStorageTime))
+                                       {
+                                               qDebug() << "Query Failed: " << sqlUpdateStorageTime;
+                                               throw std::exception();
+                                       }
+
+                                       qDebug() << "Committing.";
+                                       db.commit();
+                               }
+                               catch(...)
+                               {
+                                       qDebug() << "Rolling back.";
+                                       db.rollback();
+                               }
+                       }
+                       else
+                               qDebug() << "Unable to start transaction.";
+               }
        }
        else
+               throw std::runtime_error("Cannot open database: Unable to establish database connection");
+}
+
+// Reorder the DB IDs as Nokia are guilty of both premature
+// optimisation as well as closed source UIs...
+// NOTE: The InsertedID list will be invalid after this so call it last...
+void RtcomEventLogger::Reindex()
+{
+       // Set up the database connection...
+       QSqlDatabase db(QSqlDatabase::addDatabase("QSQLITE"));
+
+       db.setDatabaseName(CurrentSettings().DBPath());
+       if(db.open())
        {
                // Reorder the evnts by their start time
                uint changesRequired(0);
@@ -393,7 +443,7 @@ void RtcomEventLogger::Reindex()
                                                        if(min == 0)
                                                                min = one;
 
-                                                       qDebug() << "( " << one << ", " << two << " )";
+                                                       //qDebug() << "( " << one << ", " << two << " )";
                                                        mapping.insert(one, two);
                                                }
                                        }
@@ -431,23 +481,23 @@ void RtcomEventLogger::Reindex()
                        int val(min);
                        sequence.append(0);
                        sequence.append(val);
-                       qDebug().nospace() << "val1: " << val << ", ";
+                       //qDebug().nospace() << "val1: " << val << ", ";
 
                        while((val = mapping[val]) && val != min)
                        {
                                sequence.append(val);
-                               qDebug().nospace() << val << ", ";
+                               //qDebug().nospace() << val << ", ";
                        }
                        sequence.append(0);
 
-                       qDebug().nospace() << "seq: ";
+                       //qDebug().nospace() << "seq: ";
                        QList<QPair<int,int> > updates;
                        int last(sequence.first());
                        foreach(int seq, sequence)
                        {
                                if(seq != last)
                                {
-                                       qDebug().nospace() << seq << ", " << last << ", ";
+                                       //qDebug().nospace() << seq << ", " << last << ", ";
                                        updates.append(QPair<int,int>(seq, last));
                                }
 
@@ -482,7 +532,7 @@ void RtcomEventLogger::Reindex()
                                }
                        }
 
-                       qDebug() << query;
+                       //qDebug() << query;
 
                        QSqlQuery * UpdateQuery(new QSqlQuery( db ));
                        if(UpdateQuery != NULL)
@@ -496,9 +546,7 @@ void RtcomEventLogger::Reindex()
                                        {
                                                for( QStringList::const_iterator currentStatement(statements.constBegin()); currentStatement != statements.constEnd(); ++currentStatement)
                                                {
-                                                       if ( UpdateQuery->exec( *currentStatement ))
-                                                               qDebug() << "Query OK, " << UpdateQuery->numRowsAffected() << " rows affected.";
-                                                       else
+                                                       if (!UpdateQuery->exec(*currentStatement))
                                                        {
                                                                qDebug() << "Query Failed: " << *currentStatement;
                                                                throw std::exception();
@@ -519,106 +567,27 @@ void RtcomEventLogger::Reindex()
                        }
                }while(changesRequired > 0);
 
-               // Update the group cache so the last events are correct
-               {
-                       qDebug() << "Updating most recent events.";
-
-                       // Grab group UIDs from group cache
-                       QSqlQuery * dbq(new QSqlQuery( db ));
-                       dbq->setForwardOnly( true );
-
-                       const char * groupUIDListSQL("SELECT group_uid FROM GroupCache");
-                       if (dbq->exec(groupUIDListSQL))
-                       {
-                               qDebug() << "Query OK, " << dbq->numRowsAffected() << " rows affected.";
-                               qDebug() << "GroupUIDs:";
-
-                               QSet<QString> groupUIDs;
-                               while( dbq->next() )
-                               {
-                                       QString groupUID(dbq->value(0).value<QString>());
-
-                                       qDebug() << groupUID;
-                                       groupUIDs.insert(groupUID);
-                               }
-
-                               // Iterate over group UIDS
-                               if(groupUIDs.count() > 0)
-                               {
-                                       // Build a batch statement to update every group with
-                                       // the most recent event
-
-                                       // Ignore 'data' failures (i.e. no events but present in the
-                                       // cache)- something else's been monkeying with the DB, and
-                                       // we can't account for everything.
-                                       const QString updateGroupCacheWithLatestEventsSQL(
-                                               "UPDATE OR IGNORE GroupCache SET event_id = "
-                                                       "(SELECT id FROM events WHERE group_uid = \"%1\" "
-                                                       " ORDER BY id DESC LIMIT 1)"
-                                               " WHERE group_uid = \"%1\";");
-                                       QString updateGroupCacheWithLatestEventsBatchSQL;
-                                       foreach(QString groupUID, groupUIDs)
-                                       {
-                                               updateGroupCacheWithLatestEventsBatchSQL.append(
-                                                       updateGroupCacheWithLatestEventsSQL
-                                                       .arg(groupUID)
-                                                       ).append("\n");
-                                       }
-
-                                       // Execute the statement in single-statement chunks thanks
-                                       // to QT's inability to call the SQLite function supporting
-                                       // multiple statements
-
-                                       QSqlQuery * setLatestEventInGroupCacheSQL(new QSqlQuery( db ));
-                                       if(NULL != setLatestEventInGroupCacheSQL)
-                                       {
-                                               setLatestEventInGroupCacheSQL->setForwardOnly( true );
-
-                                               if(db.transaction())
-                                               {
-                                                       QStringList statements = updateGroupCacheWithLatestEventsBatchSQL.trimmed().split(";", QString::SkipEmptyParts);
-                                                       try
-                                                       {
-                                                               for( QStringList::const_iterator currentStatement(statements.constBegin()); currentStatement != statements.constEnd(); ++currentStatement)
-                                                               {
-                                                                       if ( setLatestEventInGroupCacheSQL->exec( *currentStatement ))
-                                                                               qDebug() << "Query OK, " << setLatestEventInGroupCacheSQL->numRowsAffected() << " rows affected.";
-                                                                       else
-                                                                       {
-                                                                               qDebug() << "Query Failed: " << *currentStatement;
-                                                                               throw std::exception();
-                                                                       }
-                                                               }
-
-                                                               qDebug() << "Committing.";
-                                                               db.commit();
-                                                       }
-                                                       catch(...)
-                                                       {
-                                                               qDebug() << "Rolling back.";
-                                                               db.rollback();
-                                                       }
-                                               }
-                                               else
-                                                       qDebug() << "Unable to start transaction.";
-                                       }
-                               }
-                       }
-                       else
-                       {
-                               qDebug() << "SQL EXEC Error: "<< "EXEC query failed";
-                               qDebug() << "Query: " << groupUIDListSQL;
-                       }
-               }
-
                qDebug() << "Closing.";
                db.close();
                QSqlDatabase::removeDatabase( "QSQLITE" );
        }
+       else
+               throw std::runtime_error("Cannot open database: Unable to establish database connection");
 
        return;
 }
 
+QStringList RtcomEventLogger::IntsToStringList(QList<uint> &values)
+{
+       QStringList returnValues;
+       returnValues.reserve(values.count());
+
+       foreach(uint value, values)
+               returnValues.append(QString::number(value));
+
+       return returnValues;
+}
+
 QDebug operator<<(QDebug dbg, RTComElEvent &event)
 {
        dbg.nospace() << "\tid:\t\t" << event.fld_id << "\n";
@@ -626,10 +595,10 @@ QDebug operator<<(QDebug dbg, RTComElEvent &event)
        dbg.nospace() << "\tservice:\t" << event.fld_service << "\n";
        dbg.nospace() << "\tevt_typ_id:\t" << event.fld_event_type_id << "\n";
        dbg.nospace() << "\tevt_typ:\t" << event.fld_event_type << "\n";
-       dbg.nospace() << "\tstore-time:\t" << QDateTime::fromTime_t(event.fld_storage_time) << "\n";
-       dbg.nospace() << "\tstart-time:\t" << QDateTime::fromTime_t(event.fld_start_time) << "\n";
-       dbg.nospace() << "\tend-time:\t\t" << QDateTime::fromTime_t(event.fld_end_time) << "\n";
-       dbg.nospace() << "\tis-read:\t\t" << (event.fld_is_read ? "true" : "false") << "\n";
+       dbg.nospace() << "\tstore-time:\t" << QDateTime::fromTime_t(event.fld_storage_time).toUTC() << "\n";
+       dbg.nospace() << "\tstart-time:\t" << QDateTime::fromTime_t(event.fld_start_time).toUTC() << "\n";
+       dbg.nospace() << "\tend-time:\t" << QDateTime::fromTime_t(event.fld_end_time).toUTC() << "\n";
+       dbg.nospace() << "\tis-read:\t" << (event.fld_is_read ? "true" : "false") << "\n";
        dbg.nospace() << "\tdirection:\t" << (event.fld_outgoing ? "Outgoing" : "Incoming") << "\n";
        dbg.nospace() << "\tflags:\t\t" << "0x" << QString::number(event.fld_flags, 16) << "\n";
        dbg.nospace() << "\tbytes sent:\t" << event.fld_bytes_sent << "\n";
@@ -638,6 +607,7 @@ QDebug operator<<(QDebug dbg, RTComElEvent &event)
        dbg.nospace() << "\tlocal-name:\t" << event.fld_local_name << "\n";
        dbg.nospace() << "\tremote-uid:\t" << event.fld_remote_uid << "\n";
        dbg.nospace() << "\tremote-name:\t" << event.fld_remote_name << "\n";
+       dbg.nospace() << "\tremote-ebid:\t" << event.fld_remote_ebook_uid << "\n";
        dbg.nospace() << "\tchannel:\t\t" << event.fld_channel << "\n";
        dbg.nospace() << "\tfree-text:\t" << event.fld_free_text << "\n";
        dbg.nospace() << "\tgroup-uid:\t" << event.fld_group_uid << "\n";