Commit e5cbf7e0 authored by Andras Mantia's avatar Andras Mantia
Browse files

Commit the preliminary version of "store payload in files" functionality.

svn path=/trunk/kdesupport/akonadi/; revision=922019
parent 9f4bcf1c
......@@ -106,6 +106,7 @@ set(libakonadiprivate_SRCS
src/storage/query.cpp
src/storage/querybuilder.cpp
src/storage/transaction.cpp
src/storage/parthelper.cpp
src/tracer.cpp
src/dbustracer.cpp
src/filetracer.cpp
......
......@@ -220,6 +220,7 @@ void AkonadiServer::startDatabaseProcess()
const QString dataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) );
const QString akDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/" ) );
const QString miscDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) );
const QString fileDataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/file_db_data" ) );
// generate config file
const QString globalConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-global.conf" ) );
......
......@@ -59,6 +59,9 @@ public:
protected Q_SLOTS:
void slotDisconnected();
/**
* New data arrived from the client. Creates a handler for it and passes the data to the handler.
*/
void slotNewData();
void slotResponseAvailable( const Response& );
void slotConnectionStateChange( ConnectionState );
......
......@@ -18,6 +18,7 @@
*/
#include "cachecleaner.h"
#include "storage/parthelper.h"
#include "storage/datastore.h"
#include "storage/selectquerybuilder.h"
......@@ -73,8 +74,9 @@ void CacheCleaner::cleanCache()
qb.addValueCondition( Part::nameFullColumnName(), Query::NotIn, collection.cachePolicyLocalParts().split( QLatin1String(" ") ) );
if ( !qb.exec() )
continue;
QList<Part> parts = qb.result();
Part::List parts = qb.result();
PartHelper::loadData(parts);
if ( parts.isEmpty() )
continue;
qDebug() << "found" << parts.count() << "item parts to expire in collection" << collection.name();
......@@ -82,7 +84,7 @@ void CacheCleaner::cleanCache()
// clear data field
for ( int i = 0; i < parts.count(); ++i) {
parts[ i ].setData( QByteArray() );
if ( !parts[ i ].update() )
if ( !PartHelper::update(&(parts[ i ])) )
qDebug() << "failed to update item part" << parts[ i ].id();
}
loopsWithExpiredItem++;
......
......@@ -22,10 +22,12 @@
namespace Akonadi {
// rfc1730 section 3
/** The state of the client
*/
enum ConnectionState {
NonAuthenticated,
Authenticated,
Selected,
NonAuthenticated, ///< Not yet authenticated
Authenticated, ///< The client is authenticated
Selected,
LoggingOut
};
......
......@@ -138,6 +138,7 @@ bool Akonadi::Append::commit()
Part part;
part.setName( QLatin1String( "PLD:RFC822" ) );
part.setData( m_data );
qDebug() << "Data appended " << m_data;
part.setPimItemId( item.id() );
QList<Part> parts;
parts.append( part );
......
......@@ -68,6 +68,7 @@ bool Copy::handleLine(const QByteArray & line)
bool Copy::copyItem(const PimItem & item, const Collection & target)
{
qDebug() << "Copy::copyItem";
DataStore *store = connection()->storageBackend();
PimItem newItem = item;
newItem.setId( -1 );
......
......@@ -26,6 +26,7 @@
#include "response.h"
#include "storage/selectquerybuilder.h"
#include "resourceinterface.h"
#include "../storage/parthelper.h"
#include <QtCore/QStringList>
#include <QtCore/QUuid>
......@@ -240,7 +241,7 @@ bool Fetch::handleLine( const QByteArray& line )
}
QByteArray partName = partQuery.query().value( partQueryNameColumn ).toString().toUtf8();
QByteArray part = partQuery.query().value( partQueryNameColumn ).toString().toUtf8();
QByteArray data = partQuery.query().value( partQueryDataColumn ).toByteArray();
QByteArray data = PartHelper::translateData(id, partQuery.query().value( partQueryDataColumn ).toByteArray());
int version = partQuery.query().value( partQueryVersionColumn ).toInt();
if ( version != 0 ) { // '0' is the default, so don't send it
part += "[" + QByteArray::number( version ) + "]";
......@@ -390,7 +391,10 @@ void Fetch::retrieveMissingPayloads(const QStringList & payloadList)
}
QString partName = partQuery.query().value( partQueryNameColumn ).toString();
if ( partName.startsWith( QLatin1String( "PLD:" ) ) ) {
if ( partQuery.query().value( partQueryDataColumn ).toByteArray().isNull() ) {
qint64 partId = partQuery.query().value( partQueryIdColumn ).toLongLong();
QByteArray data = PartHelper::translateData(partId, partQuery.query().value( partQueryDataColumn ).toByteArray());
data = PartHelper::translateData(partId, data);
if ( data.isNull() ) {
if ( mFullPayload && !missingParts.contains( partName ) )
missingParts << partName;
} else {
......
......@@ -30,6 +30,7 @@
#include "handlerhelper.h"
#include "../../libs/imapparser_p.h"
#include "storage/selectquerybuilder.h"
#include "storage/parthelper.h"
using namespace Akonadi;
......@@ -183,6 +184,7 @@ bool Store::handleLine( const QByteArray& line )
if ( !qb.exec() )
return failureResponse( "Unable to check item part existence" );
Part::List result = qb.result();
PartHelper::loadData(result);
if ( !result.isEmpty() ) {
part = result.first();
}
......@@ -196,10 +198,11 @@ bool Store::handleLine( const QByteArray& line )
part.setVersion( version );
part.setPimItemId( pimItems[ i ].id() );
if ( part.isValid() ) {
if ( !part.update() )
if ( !PartHelper::update(&part) )
return failureResponse( "Unable to update item part" );
} else {
if ( !part.insert() )
qDebug() << "insert from Store::handleLine";
if ( !PartHelper::insert(&part) )
return failureResponse( "Unable to add item part" );
}
store->updatePimItem( pimItems[ i ] );
......@@ -324,7 +327,7 @@ bool Store::deleteParts( const PimItem &item, const QList<QByteArray> &parts )
QList<QByteArray> partList;
for ( int i = 0; i < parts.count(); ++i ) {
Part part = Part::retrieveByName( QString::fromUtf8( parts[ i ] ) );
Part part = PartHelper::retrieveByName( QString::fromUtf8( parts[ i ] ) );
if ( !part.isValid() )
continue;
......
......@@ -67,7 +67,7 @@
<table name="SchemaVersion">
<comment>Contains the schema version of the database.</comment>
<column name="version" type="int" default="0" properties="NOT NULL"/>
<data columns="version" values="10"/>
<data columns="version" values="11"/>
</table>
<table name="Resource">
......@@ -148,6 +148,7 @@
<column name="data" type="QByteArray"/>
<column name="datasize" type="int" properties="NOT NULL"/>
<column name="version" type="int" properties="DEFAULT 0"/>
<column name="external" type="bool" default="false" />
<index name="pimItemIdNameIndex" columns="pimItemId,name" unique="true"/>
</table>
......
......@@ -32,6 +32,7 @@
#include "countquerybuilder.h"
#include "xdgbasedirs_p.h"
#include "akdebug.h"
#include "parthelper.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
......@@ -229,7 +230,7 @@ bool DataStore::removeItemParts( const PimItem &item, const QList<QByteArray> &p
Part::List existingParts = item.parts();
foreach ( Part part, existingParts )
if( parts.contains( part.name().toLatin1() ) )
part.remove();
PartHelper::remove(&part);
mNotificationCollector->itemChanged( item );
return true;
......@@ -405,7 +406,8 @@ bool DataStore::appendPimItem( const QList<Part> & parts,
part.setPimItemId( pimItem.id() );
part.setDatasize( part.data().size() );
if( !part.insert() )
qDebug() << "Insert from DataStore::appendPimItem";
if( !PartHelper::insert(&part) )
return false;
}
}
......@@ -477,7 +479,7 @@ bool DataStore::cleanupPimItem( const PimItem &item )
if ( !item.clearFlags() )
return false;
if ( !Part::remove( Part::pimItemIdColumn(), item.id() ) )
if ( !PartHelper::remove( Part::pimItemIdColumn(), item.id() ) )
return false;
if ( !PimItem::remove( PimItem::idColumn(), item.id() ) )
return false;
......
......@@ -223,7 +223,7 @@ class AKONADIPRIVATE_EXPORT <xsl:value-of select="$className"/> : public Entity
static bool clear<xsl:value-of select="@table2"/>s( qint64 id );
</xsl:for-each>
protected:
// protected:
// delete records
static bool remove( const QString &amp;column, const QVariant &amp;value );
......
/***************************************************************************
* Copyright (C) 2009 by Andras Mantia <amantia@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "parthelper.h"
#include "entities.h"
#include "selectquerybuilder.h"
#include "../../libs/xdgbasedirs_p.h"
#include <QDir>
#include <QFile>
#include <QDebug>
//set to true in order to store the payload data in a file
#define AKONADI_USE_FILE_DATA false
using namespace Akonadi;
PartHelper::PartHelper()
{
}
PartHelper::~PartHelper()
{
}
bool PartHelper::update( Part *part )
{
if (!part)
return false;
if (AKONADI_USE_FILE_DATA)
{
QString fileName = PartHelper::fileNameForId( part->id() );
QFile file(fileName);
if (file.open( QIODevice::WriteOnly | QIODevice::Truncate ))
{
QByteArray data = part->data();
//qDebug() << "Update part file " << part->id() << "_data with " << QString::fromUtf8(data).left(50);
file.write( data );
QByteArray fileNameData = fileName.toLocal8Bit();
part->setData( fileNameData );
part->setDatasize( fileNameData.size() );
part->setExternal (true );
file.close();
} else
{
return false;
}
}
return part->update();
}
bool PartHelper::insert( Part *part, qint64* insertId )
{
if (!part)
return false;
//qDebug() << "Insert original data " << part->data();
QByteArray fileNameData("");
QByteArray data;
//it is needed to insert first the metadata so a new id is generated for the part,
//and we need this id for the payload file name
if (AKONADI_USE_FILE_DATA)
{
data = part->data();
part->setData( fileNameData );
part->setDatasize( fileNameData.size() );
part->setExternal(true);
}
bool result = part->insert( insertId );
if (AKONADI_USE_FILE_DATA && result)
{
QString fileName = PartHelper::fileNameForId( part->id() );
QFile file( fileName );
if (file.open( QIODevice::WriteOnly | QIODevice::Truncate ))
{
//qDebug() << "Insert part file " << part->id() << "_data with " << QString::fromUtf8(data).left(50);
file.write(data);
fileNameData = fileName.toLocal8Bit();
part->setData(fileNameData);
part->setDatasize(fileNameData.size());
part->update();
file.close();
} else
{
return false;
}
}
return result;
}
bool PartHelper::remove( Akonadi::Part *part )
{
if (!part)
return false;
if (AKONADI_USE_FILE_DATA && part->external())
{
//qDebug() << "remove part file " << part->id();
QString fileName = PartHelper::fileNameForId( part->id() );
QFile file( fileName );
file.remove();
}
return part->remove();
}
bool PartHelper::remove(qint64 id)
{
if (AKONADI_USE_FILE_DATA)
{
//qDebug() << "remove part file " <<id;
QString fileName = PartHelper::fileNameForId( id );
QFile file( fileName );
file.remove();
}
return Part::remove(id);
}
bool PartHelper::remove( const QString &column, const QVariant &value )
{
if (AKONADI_USE_FILE_DATA)
{
SelectQueryBuilder<Part> builder;
builder.addValueCondition( column, Query::Equals, value );
if ( !builder.exec() ) {
qDebug() << "Error selecting records to be deleted from table"
<< Part::tableName() << builder.query().lastError().text();
return false;
}
Part::List parts = builder.result();
Part::List::Iterator it = parts.begin();
Part::List::Iterator end = parts.end();
for ( ; it != end; ++it )
{
//qDebug() << "remove part file " <<value.toString();
QString fileName = PartHelper::fileNameForId( (*it).id() );
QFile file( fileName );
file.remove();
}
}
return Part::remove( column, value );
}
void PartHelper::loadData( Part::List &parts )
{
if (AKONADI_USE_FILE_DATA)
{
Part::List::Iterator it = parts.begin();
Part::List::Iterator end = parts.end();
for ( ; it != end; ++it )
{
loadData( (*it) );
}
}
}
void PartHelper::loadData( Part &part )
{
if (AKONADI_USE_FILE_DATA)
{
if (part.external())
{
QString fileName = PartHelper::fileNameForId( part.id() );
//qDebug() << "loadData " << fileName;
QFile file( fileName );
if (file.open( QIODevice::ReadOnly ))
{
QByteArray data = file.readAll();
part.setData(data);
part.setDatasize( data.size() );
//qDebug() << "load part file " << part.id() << QString::fromUtf8(data).left(50);
file.close();
}
}
}
}
QByteArray PartHelper::translateData( qint64 id, const QByteArray &data )
{
if (AKONADI_USE_FILE_DATA)
{
//qDebug() << "translateData " << id;
QString fileName = PartHelper::fileNameForId( id );
QFile file( fileName );
if (file.open( QIODevice::ReadOnly ))
{
QByteArray payload = file.readAll();
file.close();
return payload;
} else
return data;
} else
return data;
}
/** Returns the record with id @p id. */
Part PartHelper::retrieveById( qint64 id )
{
Part part = Part::retrieveById( id );
loadData(part);
return part;
}
/** Returns the record with name @p name. */
Part PartHelper::retrieveByName( const QString &name )
{
Part part = Part::retrieveByName( name );
loadData(part);
return part;
}
QString PartHelper::fileNameForId( qint64 id )
{
const QString dataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/file_db_data" ) ) + QDir::separator();
return dataDir + QString::number(id);
}
/***************************************************************************
* Copyright (C) 2009 by Andras Mantia <amantia@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef PARTHELPER_H
#define PARTHELPER_H
#include <QtGlobal>
#include "entities.h"
class QString;
class QVariant;
namespace Akonadi
{
/**
A specialized Part class that stores data in a file instead of the database.
@author Andras Mantia <amantia@kde.org>
*/
class PartHelper
{
public:
PartHelper();
~PartHelper();
static bool update( Part *part );
static bool insert( Part *part, qint64* insertId = 0 );
static bool remove( Part *part);
static bool remove( qint64 id );
static bool remove( const QString &column, const QVariant &value );
static void loadData( Part::List &parts );
static void loadData( Part &part );
static QByteArray translateData( qint64 id, const QByteArray &data );
/** Returns the record with id @p id. */
static Part retrieveById( qint64 id );
/** Returns the record with name @p name. */
static Part retrieveByName( const QString &name );
static QString fileNameForId( qint64 id );
};
}
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment