mtpdataproviders/mtpimagedp/mediasyncserver/src/cmediasyncdatabase.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:11:40 +0200
changeset 0 d0791faffa3f
permissions -rw-r--r--
Revision: 201003 Kit: 201005

// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

/**
 @file
 @internalTechnology
*/

#include <bautils.h>
#include <mdesession.h>
#include <mdequery.h>
#include <mdeconstants.h>

#include "cmediasyncserverdef.h"
#include "cmediasyncdatabase.h"
#include "cmediasyncdatawriter.h"

__FLOG_STMT(_LIT8(KComponent,"MediaSyncDatabase");)

const TInt KCompactThreshold = 50;
const TInt KMaxRetryTimes = 3;
const TInt KDelayPeriod = 3 * 1000000;

CMediaSyncDatabase* CMediaSyncDatabase::NewL(RFs& aFs)
    {
    CMediaSyncDatabase* self = new (ELeave) CMediaSyncDatabase(aFs);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

void CMediaSyncDatabase::ConstructL()
    {
    __FLOG_OPEN(KMSSSubsystem, KComponent);
    __FLOG(_L8("CMediaSyncDatabase::ConstructL - Entry"));

    //Connect to the file server
    User::LeaveIfError(iFs.Connect());

    TFileName databasePath;
    iFs.PrivatePath(databasePath);
    TDriveUnit driveNum = RFs::GetSystemDrive();
    databasePath.Insert(0, driveNum.Name());
    databasePath.Append(KMssDbName);

    CreateTableL(databasePath);    
    
    User::LeaveIfError(iBatched.Open(iDatabase, KImageTableName, RDbRowSet::EUpdatable));
    
    __FLOG(_L8("CMediaSyncDatabase::ConstructL - Exit"));
    }

CMediaSyncDatabase::CMediaSyncDatabase(RFs& aFs) :
    iFs(aFs),
    iDbCorrupt(EFalse),
    iSavePosition(EFalse)
    {
    }

CMediaSyncDatabase::~CMediaSyncDatabase()
    {
    __FLOG(_L8("CMediaSyncDatabase::~CMediaSyncDatabase - Entry"));
    
    iBatched.Close();
    iDatabase.Close();
    
    __FLOG(_L8("CMediaSyncDatabase::~CMediaSyncDatabase - Exit"));
    __FLOG_CLOSE;
    }

void CMediaSyncDatabase::CreateTableL(const TDesC& aDbFile)
    {
    __FLOG(_L8("CMediaSyncDatabase::CreateTableL - Entry"));
    
    _LIT(KSQLCreateTable, "CREATE TABLE ImageStore(ObjectId UNSIGNED INTEGER, NotificationType UNSIGNED INTEGER, URI VARCHAR(255))");           
    
    TInt err = KErrNone;
    if (!BaflUtils::FileExists(iFs, aDbFile))
        {
        __FLOG(_L8("CreateTableL - Table ImageStore does not exist"));
        
        BaflUtils::EnsurePathExistsL(iFs, aDbFile);
        
        User::LeaveIfError(iDatabase.Create(iFs, aDbFile));
        User::LeaveIfError(iDatabase.Execute(KSQLCreateTable));
        TRAP_IGNORE(CreateTabIndexL());
        }    
    else
        {
        //Open the database
        TBool recreateDbFile = EFalse;
        err = iDatabase.Open(iFs, aDbFile);
        if (err == KErrNone)
            {
            if (iDatabase.IsDamaged())
                {
                recreateDbFile = (iDatabase.Recover() == KErrNone) ? EFalse : ETrue;
                }
            }
        else
            {
            recreateDbFile = ETrue;
            }
        
        if (recreateDbFile)
            {
            __FLOG_VA((_L8("CreateTableL - Open Table ImageStore failed: %d"), err));
            iDatabase.Close();

            TInt retryCount = KMaxRetryTimes;
            TInt result = KErrNone;            
            for (; retryCount > 0; retryCount--)
                {
                result = BaflUtils::DeleteFile(iFs, aDbFile);
                if (result == KErrNone)
                    {
                    // We have succesfully delete corrupt database file
                    break;
                    }       
                else
                    {
                    User::After(KDelayPeriod);
                    }
                }
            
            User::LeaveIfError(result);
            User::LeaveIfError(iDatabase.Create(iFs, aDbFile));
            User::LeaveIfError(iDatabase.Execute(KSQLCreateTable));
            TRAP_IGNORE(CreateTabIndexL());
            iDbCorrupt = ETrue;          
            }
        }    
    
    __FLOG(_L8("CMediaSyncDatabase::CreateTableL - Exit"));
    }

void CMediaSyncDatabase::CreateTabIndexL()
    {    
    __FLOG(_L8("CMediaSyncDatabase::CreateTabIndexL - Entry"));
    
    _LIT(KSQLCreateCombinedIndexText,"CREATE UNIQUE INDEX CombinedIndex on ImageStore (ObjectId, NotificationType)");      
    User::LeaveIfError(iDatabase.Execute(KSQLCreateCombinedIndexText));
    
    __FLOG(_L8("CMediaSyncDatabase::CreateTabIndexL - Exit"));
    }

void CMediaSyncDatabase::SaveNotificationsL(const RArray<TItemId>& aObjectIdArray, TObserverNotificationType aType, CMdESession& aSession)
    {    
    iDatabase.Begin();  

    switch (aType)
        {
        case ENotifyAdd:
            __FLOG(_L8("CMediaSyncDatabase::SaveNotificationsL Addition - Entry"));
            SaveAddNotificationsL(aObjectIdArray, aSession);
            break;
            
        case ENotifyRemove:
            __FLOG(_L8("CMediaSyncDatabase::SaveNotificationsL Remove - Entry"));
            SaveWithoutUriL(aObjectIdArray, KMssRemoval);
            break;
            
        case ENotifyModify:
            __FLOG(_L8("CMediaSyncDatabase::SaveNotificationsL Modify - Entry"));
            SaveAndCheckWithUriL(aObjectIdArray, KMssChange, aSession);
            break;
            
        default:
            __FLOG_VA((_L8("SaveNotificationsL - Unknown argument: %d"), aType));
            User::Leave(KErrArgument);
            break;
        }
   
    iDatabase.Commit();
    
    __FLOG(_L8("CMediaSyncDatabase::SaveNotificationsL - Exit"));
    }

inline TBool CMediaSyncDatabase::OptimizeL(TItemId aObjectId, TUint aType)
    {    
    return OptimizeL(aObjectId, aType, KNullDesC);
    }

void CMediaSyncDatabase::Rollback()
    {
    __ASSERT_DEBUG(iDatabase.InTransaction(), User::Invariant());
    iDatabase.Rollback();
    }

TBool CMediaSyncDatabase::OptimizeL(TItemId aObjectId, TUint aType, const TDesC& aUri)
    {
    __FLOG(_L8("CMediaSyncDatabase::OptimizeL - Entry"));
    
    TBool saveNotification = ETrue;
    
    switch (aType)
        {                
    case KMssChange:
        if ( UpdateUriColumnL(aObjectId, KMssAddition, aUri) ||
             UpdateUriColumnL(aObjectId, KMssChange, aUri) )
            {
            saveNotification = EFalse;// ignore this update notification
            }
        __FLOG_VA((_L8("OptimizeL - KMssChange ObjectId: %u, Ignore saving: %d"), aObjectId, saveNotification));
        break;
                
    case KMssPresent:
        if (RemoveNotificationL(aObjectId, KMssNotPresent))
            {
            saveNotification = EFalse;// ignore this present notification
            }
        __FLOG_VA((_L8("OptimizeL - KMssPresent ObjectId: %u, Ignore saving: %d"), aObjectId, saveNotification));
        break;        
        
    case KMssRemoval:
        if (RemoveNotificationL(aObjectId, KMssAddition))
            {
            saveNotification = EFalse;// ignore this removal notification
            }        
        else
            {
            RemoveNotificationL(aObjectId, KMssChange);
            }
        __FLOG_VA((_L8("OptimizeL - KMssRemoval ObjectId: %u, Ignore saving: %d"), aObjectId, saveNotification));
        break;
        
    case KMssNotPresent:
        if (RemoveNotificationL(aObjectId, KMssPresent))
            {
            saveNotification = EFalse;// ignore this not present notification
            }
        __FLOG_VA((_L8("OptimizeL - KMssNotPresent ObjectId: %u, Ignore saving: %d"), aObjectId, saveNotification));
        break;
        
    default:
        // Nothing to do
        break;
        }
    
    __FLOG(_L8("CMediaSyncDatabase::OptimizeL - Exit"));
    
    return saveNotification;
    }

void CMediaSyncDatabase::SaveNotificationsL(const RArray<TItemId>& aObjectIdArray, TBool aPresent, CMdESession& aSession)
    {        
    iDatabase.Begin();
   
    if (aPresent)
        {
        __FLOG(_L8("CMediaSyncDatabase::SaveNotificationsL Present - Entry"));
        SaveAndCheckWithUriL(aObjectIdArray, KMssPresent, aSession);
        }
    else
        {
        __FLOG(_L8("CMediaSyncDatabase::SaveNotificationsL Not Present - Entry"));
        SaveWithoutUriL(aObjectIdArray, KMssNotPresent);
        }      
    
    iDatabase.Commit();  
    
    __FLOG(_L8("CMediaSyncDatabase::SaveNotificationsL Present - Exit"));
    }

void CMediaSyncDatabase::SaveAddNotificationsL(const RArray<TItemId>& aObjectIdArray, CMdESession& aSession)
    {
    __FLOG(_L8("CMediaSyncDatabase::SaveAddNotificationsL - Entry"));
    
    CMdENamespaceDef& defaultNamespaceDef = aSession.GetDefaultNamespaceDefL();
    CMdEObjectDef& imageObjDef = defaultNamespaceDef.GetObjectDefL(MdeConstants::Image::KImageObject); 

    TInt objectCount = aObjectIdArray.Count();   
    for (TInt i(0);i < objectCount;i++)
        {       
        TItemId objectId = aObjectIdArray[i];
        CMdEObject* addObject = aSession.GetObjectL(objectId, imageObjDef);
        if (addObject)
            {
            CleanupStack::PushL(addObject);
            CleanupStack::PushL(TCleanupItem(CMediaSyncDatabase::RollbackTable, &iBatched));
            iBatched.InsertL();
            iBatched.SetColL(1, (TUint32)objectId);
            iBatched.SetColL(2, KMssAddition);
            iBatched.SetColL(3, addObject->Uri());
            iBatched.PutL();
            CleanupStack::Pop(&iBatched);            
            __FLOG_VA((_L16("CMediaSyncDatabase::SaveAndCheckWithUriL - ObjectId:%u, Type:%u, URI:%S"), objectId, KMssAddition, &addObject->Uri()));
            CleanupStack::PopAndDestroy(addObject); 
            }                                 
        }      
    
    __FLOG(_L8("CMediaSyncDatabase::SaveAddNotificationsL - Exit"));
    }

void CMediaSyncDatabase::SaveAndCheckWithUriL(const RArray<TItemId>& aObjectIdArray, TUint aType, CMdESession& aSession)
    {
    __FLOG(_L8("CMediaSyncDatabase::SaveAndCheckWithUriL - Entry"));
    
    CMdENamespaceDef& defaultNamespaceDef = aSession.GetDefaultNamespaceDefL();
    CMdEObjectDef& imageObjDef = defaultNamespaceDef.GetObjectDefL(MdeConstants::Image::KImageObject); 
    CMdEPropertyDef& itemTypePropDef = imageObjDef.GetPropertyDefL(MdeConstants::Object::KItemTypeProperty);    

    TInt objectCount = aObjectIdArray.Count();   
    for (TInt i(0);i < objectCount;i++)
        {       
        TItemId objectId = aObjectIdArray[i];          
        CMdEObject* changeObject = aSession.GetObjectL(objectId, imageObjDef);
        if (changeObject)
            {
            CleanupStack::PushL(changeObject);            
            //only support jpeg format image files             
            CMdEProperty* itemType = NULL;
            TInt err = changeObject->Property(itemTypePropDef, itemType);
            
            if (err >= KErrNone && itemType != NULL && itemType->TextValueL().Compare(KJpegMime) == 0)
                {                        
                if (OptimizeL(objectId, aType, changeObject->Uri()))
                    {                    
                    CleanupStack::PushL(TCleanupItem(CMediaSyncDatabase::RollbackTable, &iBatched));
                    iBatched.InsertL();
                    iBatched.SetColL(1, (TUint32)objectId);
                    iBatched.SetColL(2, aType);                    
                    iBatched.SetColL(3, changeObject->Uri());
                    iBatched.PutL();                    
                    CleanupStack::Pop(&iBatched);
                    __FLOG_VA((_L16("CMediaSyncDatabase::SaveAndCheckWithUriL - ObjectId:%u, Type:%u, URI:%S"), objectId, aType, &changeObject->Uri()));
                    }
                }
            CleanupStack::PopAndDestroy(changeObject);            
            }
        }  
    
    __FLOG(_L8("CMediaSyncDatabase::SaveAndCheckWithUriL - Exit"));
    }

void CMediaSyncDatabase::SaveWithoutUriL(const RArray<TItemId>& aObjectIdArray, TUint aType)
    {
    TInt objectCount = aObjectIdArray.Count();   
    for (TInt i(0);i < objectCount;i++)
        {       
        TItemId objectId = aObjectIdArray[i];        
        if (OptimizeL(objectId, aType))
            {
            CleanupStack::PushL(TCleanupItem(CMediaSyncDatabase::RollbackTable, &iBatched));
            iBatched.InsertL();
            iBatched.SetColL(1, (TUint32)objectId);
            iBatched.SetColL(2, aType);
            iBatched.PutL();
            __FLOG_VA((_L8("CMediaSyncDatabase::SaveWithoutUriL - ObjectId:%u, Type: %u"), objectId, aType));
            CleanupStack::Pop(&iBatched);
            }
        }
    
    __FLOG(_L8("CMediaSyncDatabase::SaveWithoutUriL - Exit"));
    }

TBool CMediaSyncDatabase::UpdateUriColumnL(TItemId aObjectId, TUint aType, const TDesC& aUri)
    {
    __FLOG(_L8("CMediaSyncDatabase::UpdateUriColumnL - Entry"));
    
    TBool update = EFalse;
    
    iBatched.SetIndex(KSQLCombinedIndex);
    TDbSeekMultiKey<2> seekKey;
    seekKey.Add((TUint)aObjectId);
    seekKey.Add(aType);
    if (iBatched.SeekL(seekKey))
        {
        CleanupStack::PushL(TCleanupItem(CMediaSyncDatabase::RollbackTable, &iBatched));
        iBatched.UpdateL();                 
        iBatched.SetColL(3, aUri);
        iBatched.PutL();        
        CleanupStack::Pop(&iBatched);
        update = ETrue;
        __FLOG_VA((_L16("CMediaSyncDatabase::UpdateUriColumnL - ObjectId:%u, Type:%u, URI:%S"), aObjectId, aType, &aUri));
        }    
    
    __FLOG(_L8("CMediaSyncDatabase::UpdateUriColumnL - Exit"));
    return update;
    }

void CMediaSyncDatabase::RemoveAllNotificationsL()
    {        
    _LIT(KSQLDeleteAllNotifications, "DELETE FROM ImageStore");
  
    User::LeaveIfError(iDatabase.Execute(KSQLDeleteAllNotifications));    
    iDatabase.Compact();    
    iSavePosition = EFalse;    
    
    __FLOG_VA((_L8("CMediaSyncDatabase::RemoveAllNotificationsL")));
    }

TBool CMediaSyncDatabase::RemoveNotificationL(TItemId aObjectId, TUint aType)
    {
    TBool remove = EFalse;
    
    iBatched.SetIndex(KSQLCombinedIndex);
    TDbSeekMultiKey<2> seekKey;
    seekKey.Add((TUint)aObjectId);
    seekKey.Add(aType);
    if (iBatched.SeekL(seekKey))
        {
        iBatched.DeleteL();
        CompactDatabase();
        iSavePosition = EFalse;
        remove = ETrue;
        __FLOG_VA((_L8("CMediaSyncDatabase::RemoveNotificationL - ObjectId:%u, Type: %u"), aObjectId, aType));
        }    
    return remove;
    }

void CMediaSyncDatabase::CompactDatabase()
    {
    if (++iCompactCounter > KCompactThreshold)
        {
        iDatabase.Compact();
        iCompactCounter = 0;
        }    
    }

void CMediaSyncDatabase::FetchNotificationsL(CMediaSyncDataWriter& aResulWriter, TInt aMaxtFetchCount, TBool& aIsFinished)
    {
    __FLOG(_L8("CMediaSyncDatabase::FetchNotificationsL - Entry"));
    
    _LIT(KSQLQuery, "SELECT ObjectId, NotificationType, URI FROM ImageStore");
    
    RDbView view;
    CleanupClosePushL(view);
    
    view.Prepare(iDatabase, TDbQuery(KSQLQuery));
    view.EvaluateAll();
    
    //goto the last fetch position
    if (iSavePosition)
        {
        view.GotoL(iBookmark);
        }
    else        
        {
        view.FirstL();   
        }
    
    TInt entrySize = 0;
    //tranvers records
    while (view.AtRow() && (aMaxtFetchCount > 0))
        {
        view.GetL();        
        TPtrC16 uri = view.ColDes16(3);
        
        entrySize = uri.Size();
        entrySize += sizeof(TUint32);//object id size
        entrySize += sizeof(TUint8);//type size 
        entrySize += sizeof(TUint8);//uri size
        
        if (entrySize > aResulWriter.FreeSpaceBytes())
            {
            //there is no enought space to save entry
            break;
            }
        else
            {
            aResulWriter.AppendEntryL(view.ColUint32(1), (TUint8)view.ColUint32(2), uri);
            view.NextL();
            --aMaxtFetchCount;
            }                                       
        }
    
    //save current fetch position
    if (view.AtEnd())
        {
        iSavePosition = EFalse;
        aIsFinished = ETrue;
        }
    else
        {
        iBookmark = view.Bookmark();
        iSavePosition = ETrue;
        aIsFinished = EFalse;
        }
    CleanupStack::PopAndDestroy(&view);
    
    __FLOG(_L8("CMediaSyncDatabase::FetchNotificationsL - Exit"));
    }

void CMediaSyncDatabase::RollbackTable(TAny* aTable)
    {
    reinterpret_cast<RDbTable*> (aTable)->Cancel();
    }