X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=DBBackends%2FRtcomEventLogger.cpp;h=c34a8dfe22af4faac5538cc4b30d5b9344bdf08d;hb=4a1baeefcc50f4a511faeb5dca72dcac61006522;hp=2e1ee837ec4e8f596dbbccf4856566b7f60586f8;hpb=4abcc9ab77d80562371024c243eb6b4f9f28dfcc;p=qwerkisync diff --git a/DBBackends/RtcomEventLogger.cpp b/DBBackends/RtcomEventLogger.cpp index 2e1ee83..c34a8df 100644 --- a/DBBackends/RtcomEventLogger.cpp +++ b/DBBackends/RtcomEventLogger.cpp @@ -19,18 +19,34 @@ #include "RtcomEventLogger.h" #include "EventProcessors/iEventProcessor.h" +#include "EventTypes/eEventTypes.h" #include "EventTypes/iEvent.h" +#include "EventTypes/PhoneCall.h" #include "EventTypes/SMS.h" +#include "RtcomEventLoggerComponents/TriggerDisabler.h" #include "Settings.h" #include +#include +#include + +// For reindexing +#include +#include +#include +#include +#include +#include #include #include #include +#include + using namespace DBBackends; +using namespace EventTypes; QDebug operator<<(QDebug, RTComElEvent &); QDebug operator<<(QDebug, RTComElAttachment &); @@ -44,15 +60,15 @@ RtcomEventLogger::RtcomEventLogger(const Settings &settings) : if(NULL != el) { // Grab the service IDs we want to work with - m_ServiceIDs.insert(SERVICE_ID_CALL, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_CALL")); - m_ServiceIDs.insert(SERVICE_ID_CHAT, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_CHAT")); - m_ServiceIDs.insert(SERVICE_ID_SMS, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_SMS")); - m_ServiceIDs.insert(SERVICE_ID_MMS, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_MMS")); + m_ServiceIDs.insert(EVENT_TYPE_CALL, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_CALL")); + //m_ServiceIDs.insert(EVENT_TYPE_CHAT, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_CHAT")); + m_ServiceIDs.insert(EVENT_TYPE_SMS, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_SMS")); + //m_ServiceIDs.insert(EVENT_TYPE_MMS, rtcom_el_get_service_id(el, "RTCOM_EL_SERVICE_MMS")); // Remove any service IDs that weren't found - foreach(ServiceID serviceID, m_ServiceIDs.keys()) - if(m_ServiceIDs.value(serviceID) == -1) - m_ServiceIDs.remove(serviceID); + foreach(EventTypes::eEventTypes service, m_ServiceIDs.keys()) + if(m_ServiceIDs.value(service) == -1) + m_ServiceIDs.remove(service); g_object_unref(el); } @@ -71,20 +87,35 @@ void RtcomEventLogger::Process(EventProcessors::iEventProcessor &processor) RTComEl *el = rtcom_el_new(); if(NULL != el) { + foreach(eEventTypes service, m_ServiceIDs.keys()) + ProcessService(processor, service, *el); + + g_object_unref(el); + } + else + qDebug() << "Failed to create event logger."; +} + +void RtcomEventLogger::ProcessService(EventProcessors::iEventProcessor &processor, const EventTypes::eEventTypes service, const RTComEl &el) +{ + RTComEl *el_nonconst(const_cast(&el)); + + bool incoming = CurrentSettings().ShouldProcess( Settings::INCOMING, service); + bool outgoing = CurrentSettings().ShouldProcess( Settings::OUTGOING, service); + + if(incoming || outgoing) + { // Initialise a query - RTComElQuery *query = rtcom_el_query_new(el); + RTComElQuery *query = rtcom_el_query_new(el_nonconst); if(query != NULL) { - bool incoming = CurrentSettings().ShouldProcess( Settings::TYPE_RECIEVED, Settings::EVENTTYPE_SMS); - bool outgoing = CurrentSettings().ShouldProcess( Settings::TYPE_SENT, Settings::EVENTTYPE_SMS); - // Prepare it... bool prepared = false; if(incoming && outgoing) { prepared = rtcom_el_query_prepare(query, "service-id", - m_ServiceIDs.value(SERVICE_ID_SMS), + m_ServiceIDs.value(service), RTCOM_EL_OP_EQUAL, NULL); @@ -93,7 +124,7 @@ void RtcomEventLogger::Process(EventProcessors::iEventProcessor &processor) { prepared = rtcom_el_query_prepare(query, "service-id", - m_ServiceIDs.value(SERVICE_ID_SMS), + m_ServiceIDs.value(service), RTCOM_EL_OP_EQUAL, "outgoing", @@ -107,7 +138,7 @@ void RtcomEventLogger::Process(EventProcessors::iEventProcessor &processor) if(prepared) { - RTComElIter *it = rtcom_el_get_events(el, query); + RTComElIter *it = rtcom_el_get_events(el_nonconst, query); if(it != NULL) { if(rtcom_el_iter_first(it)) @@ -120,7 +151,7 @@ void RtcomEventLogger::Process(EventProcessors::iEventProcessor &processor) // Reset the iterator and grab the actual values qDebug() << "Resetting iterator..."; g_object_unref(it); - it = rtcom_el_get_events(el, query); + it = rtcom_el_get_events(el_nonconst, query); if(it != NULL) { if(rtcom_el_iter_first(it)) @@ -135,26 +166,13 @@ void RtcomEventLogger::Process(EventProcessors::iEventProcessor &processor) RTComElEvent revent; memset(&revent, 0, sizeof(revent)); - if(rtcom_el_iter_get_values ( - it, - "id", &revent.fld_id, - "service-id", &revent.fld_service_id, - "start-time", &revent.fld_start_time, - "end-time", &revent.fld_end_time, - "local-uid", &revent.fld_local_uid, - "local-name", &revent.fld_local_name, - "remote-uid", &revent.fld_remote_uid, - "remote-name", &revent.fld_remote_name, - "is-read", &revent.fld_is_read, - "outgoing", &revent.fld_outgoing, - "free-text", &revent.fld_free_text, - NULL)) + if(rtcom_el_iter_get_full(it, &revent)) { qDebug() << revent; QList rattachments; RTComElAttachIter *at_it = rtcom_el_iter_get_attachments(it); - if(it != NULL) + if(at_it != NULL) { qDebug() << "Attachments OK"; if(rtcom_el_attach_iter_first(at_it)) @@ -200,37 +218,39 @@ void RtcomEventLogger::Process(EventProcessors::iEventProcessor &processor) } else qDebug() << "Failed to create query."; - - g_object_unref(el); } else - qDebug() << "Failed to create event logger."; + qDebug() << "Nothing to do for " << m_ServiceIDs.value(service); } EventTypes::iEvent *const RtcomEventLogger::CreateEvent(RTComElEvent &revent, QList &rattachments) { - //if(m_ServiceIDs.contains(SERVICE_ID_CALL) && revent.fld_service_id == m_ServiceIDs.value(SERVICE_ID_CALL)) - // return new EventTypes::Call(CurrentSettings(), revent, rattachments); + if(m_ServiceIDs.contains(EVENT_TYPE_CALL) && revent.fld_service_id == m_ServiceIDs.value(EVENT_TYPE_CALL)) + return new EventTypes::PhoneCall(CurrentSettings(), revent, rattachments); - //if(m_ServiceIDs.contains(SERVICE_ID_CHAT) && revent.fld_service_id == m_ServiceIDs.value(SERVICE_ID_CHAT)) + //if(m_ServiceIDs.contains(EVENT_TYPE_CHAT) && revent.fld_service_id == m_ServiceIDs.value(EVENT_TYPE_CHAT)) // return new EventTypes::Chat(CurrentSettings(), revent, rattachments); - if(m_ServiceIDs.contains(SERVICE_ID_SMS) && revent.fld_service_id == m_ServiceIDs.value(SERVICE_ID_SMS)) + if(m_ServiceIDs.contains(EVENT_TYPE_SMS) && revent.fld_service_id == m_ServiceIDs.value(EVENT_TYPE_SMS)) return new EventTypes::SMS(CurrentSettings(), revent, rattachments); - //if(m_ServiceIDs.contains(SERVICE_ID_MMS) && revent.fld_service_id == m_ServiceIDs.value(SERVICE_ID_MMS)) + //if(m_ServiceIDs.contains(EVENT_TYPE_MMS) && revent.fld_service_id == m_ServiceIDs.value(EVENT_TYPE_MMS)) // return new EventTypes::MMS(CurrentSettings(), revent, rattachments); return NULL; } +void RtcomEventLogger::PreInsert() +{ + m_TriggerDisabler = new RtcomEventLoggerComponents::TriggerDisabler(CurrentSettings()); +} + void RtcomEventLogger::Insert(EventTypes::iEvent &event, const NumberToNameLookup &numberToNameLookup) { if(EventTypes::RtcomEvent *rtcomEvent = dynamic_cast(&event)) { const uint UUID_STR_LEN(36); - int newEventID(0); _RTComEl *el(rtcom_el_new()); if(NULL != el) { @@ -254,12 +274,41 @@ void RtcomEventLogger::Insert(EventTypes::iEvent &event, const NumberToNameLooku qDebug() << *rattachments; // Add the event - newEventID = rtcom_el_add_event_full(el, revent, rheaders, rattachments, &error); - qDebug() << "new id: " << newEventID; - if(error != NULL) + 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()) < 10000) + { + if(error != NULL) + { + qDebug() << "err: " << error->message; + g_error_free(error); + error = NULL; + } + + // Don't hammer the DB when there's an error. Give it literally just a moment before retrying. + QMutex mutex; + mutex.lock(); + + QWaitCondition waitCondition; + 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() << "err: " << error->message; - g_error_free(error); + qDebug() << "new id: " << newEventID; + InsertedIDs().append(newEventID); } // Release the attachments @@ -278,17 +327,231 @@ void RtcomEventLogger::Insert(EventTypes::iEvent &event, const NumberToNameLooku return; } +void RtcomEventLogger::PostInsert() +{ + // Reorder the DB IDs as Nokia are guilty of both premature + // optimisation as well as closed source UIs... + Reindex(); + + delete m_TriggerDisabler; +} + +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() +{ + // Set up the database connection... + QSqlDatabase db(QSqlDatabase::addDatabase("QSQLITE")); + + db.setDatabaseName(CurrentSettings().DBPath()); + if(!db.open()) + { + throw std::runtime_error("Cannot open database: Unable to establish database connection"); + } + else + { + // Reorder the evnts by their start time + uint changesRequired(0); + do + { + // Note the smallest event ID found, so we have a place to start. + int min(0); + + // The required ID changes ( current, correct ); + QHash mapping; + + // Grab the current records, and determine what changes need to + // happen to get to the sorted results + { + qDebug() << "DB Opened"; + + QSqlQuery * dbq1(new QSqlQuery( db )), * dbq2(new QSqlQuery( db )); + + dbq1->setForwardOnly( true ); + dbq2->setForwardOnly( true ); + + QString s1("SELECT id, event_type_id, start_time, end_time " + " FROM Events"); + QString s2("SELECT id, event_type_id, start_time, end_time " + " FROM Events ORDER BY start_time ASC"); + + if ( dbq1->exec( s1 ) && dbq2->exec( s2 )) + { + qDebug() << "Query OK, " << dbq1->numRowsAffected() << " & " << dbq2->numRowsAffected() << " rows affected."; + + while( dbq1->next() && dbq2->next()) + { + int one (dbq1->value( 0 ).value< int >()); + int two (dbq2->value( 0 ).value< int >()); + //uint startTime( m_dbq->value( 1 ).value< uint >() ); + //uint endTime( m_dbq->value( 2 ).value< uint >() ); + + //qDebug() << "Event: " << type << ", " << startTime << ", " << endTime << ""; + //qDebug() << "( " << one << ", " << two << " )"; + + if(two != one) + { + if(min == 0) + min = one; + + //qDebug() << "( " << one << ", " << two << " )"; + mapping.insert(one, two); + } + } + } + else + { + qDebug() << "SQL EXEC Error: "<< "EXEC query failed"; + qDebug() << "Query1: " << s1; + qDebug() << "Query2: " << s1; + } + + // Clear up database connections + if ( dbq1 != NULL ) + { + qDebug() << "Cleaning up connection 1"; + + dbq1->finish(); + + delete dbq1; + dbq1 = NULL; + } + + if ( dbq2 != NULL ) + { + qDebug() << "Cleaning up connection 2"; + + dbq2->finish(); + + delete dbq2; + dbq2 = NULL; + } + } + + QList sequence; + int val(min); + sequence.append(0); + sequence.append(val); + //qDebug().nospace() << "val1: " << val << ", "; + + while((val = mapping[val]) && val != min) + { + sequence.append(val); + //qDebug().nospace() << val << ", "; + } + sequence.append(0); + + //qDebug().nospace() << "seq: "; + QList > updates; + int last(sequence.first()); + foreach(int seq, sequence) + { + if(seq != last) + { + //qDebug().nospace() << seq << ", " << last << ", "; + updates.append(QPair(seq, last)); + } + + last = seq; + } + + // Used to keep iterating until no changes are required. + // TODO: Shouldn't be required, but is. One to revisit later. + changesRequired = updates.count(); + + for( QList >::const_iterator it(updates.constBegin()); it != updates.constEnd(); ++it) + { + //qDebug().nospace() << (*it).first << ", " << (*it).second; + } + + QList tables = QList() << "Events" << "Attachments" << "Headers" << "GroupCache"; + QString query; + for( QList::const_iterator currentTable(tables.constBegin()); currentTable != tables.constEnd(); ++currentTable) + { + QString curquery = "UPDATE %3 set %4 = %1 WHERE %4 = %2;"; + for( QList >::const_iterator currentUpdate(updates.constBegin()); currentUpdate != updates.constEnd(); ++currentUpdate) + { + query.append( + curquery + .arg((*currentUpdate).second) + .arg((*currentUpdate).first) + .arg((*currentTable)) + .arg((*currentTable) == "Events" ? "id" : "event_id") + ).append("\n"); + + //qDebug().nospace() << (*it).first << ", " << (*it).second; + } + } + + //qDebug() << query; + + QSqlQuery * UpdateQuery(new QSqlQuery( db )); + if(UpdateQuery != NULL) + { + UpdateQuery->setForwardOnly( true ); + + if(db.transaction()) + { + QStringList statements = query.trimmed().split(";", QString::SkipEmptyParts); + try + { + for( QStringList::const_iterator currentStatement(statements.constBegin()); currentStatement != statements.constEnd(); ++currentStatement) + { + if (!UpdateQuery->exec(*currentStatement)) + { + qDebug() << "Query Failed: " << *currentStatement; + throw std::exception(); + } + } + + qDebug() << "Committing."; + db.commit(); + } + catch(...) + { + qDebug() << "Rolling back."; + db.rollback(); + } + } + else + qDebug() << "Unable to start transaction."; + } + }while(changesRequired > 0); + + qDebug() << "Closing."; + db.close(); + QSqlDatabase::removeDatabase( "QSQLITE" ); + } + + return; +} + QDebug operator<<(QDebug dbg, RTComElEvent &event) { dbg.nospace() << "\tid:\t\t" << event.fld_id << "\n"; - dbg.nospace() << "\tFolder:\t\t" << (event.fld_outgoing ? "Sent" : "Inbox") << "\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() << "\tlocal-uid:\t" << event.fld_local_uid << "\n"; - //dbg.nospace() << "\tlocal-name:\t" << event.fld_local_name << "\n"; + dbg.nospace() << "\tservice_id:\t" << event.fld_service_id << "\n"; + 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).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"; + dbg.nospace() << "\tbytes recv:\t" << event.fld_bytes_received << "\n"; + dbg.nospace() << "\tlocal-uid:\t" << event.fld_local_uid << "\n"; + 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() << "\tis-read:\t\t" << (event.fld_is_read ? "true" : "false") << "\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";