diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,281 @@ +// Copyright (c) 2008-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: +// + +#include +#include +#include +#include "SqlPanic.h" +#include "SqlCompactEntry.h" +#include "SqlCompactTimer.h" +#include "SqliteSymbian.h" //TSqlFreePageCallback + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +Creates a new CSqlCompactEntry instance. + +@param aFullName The full database name, including the path. +@param aConnFactoryL MSqlCompactConn factory function. +@param aSettings Background compaction settings/thresholds +@param aTimer The background compaction timer object + +When the free pages threshold reach certain the threshold, the background compaction +for this entry will be kicked-off. + +@return A pointer to the created CSqlCompactEntry instance + +@leave KErrNoMemory, an out of memory condition has occurred; + Note that the function may also leave with some other database specific + errors categorised as ESqlDbError, and other system-wide error codes. + +@panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter) +@panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL. +*/ +CSqlCompactEntry* CSqlCompactEntry::NewLC(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL, + const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer) + { + __SQLASSERT(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, ESqlPanicBadArgument); + __SQLASSERT(aConnFactoryL != NULL, ESqlPanicBadArgument); + CSqlCompactEntry* self = new (ELeave) CSqlCompactEntry(aSettings, aTimer); + CleanupStack::PushL(self); + self->ConstructL(aFullName, aConnFactoryL); + return self; + } + +/** +Destroys the CSqlCompactEntry instance. The database connection will be closed. +*/ +CSqlCompactEntry::~CSqlCompactEntry() + { + if(iState == CSqlCompactEntry::EInProgress) + { + iTimer.DeQueue(*this); + } + if(iConnection) + { + iConnection->Release(); + } + iFullName.Close(); + } + +/** +Increments the entry reference counter. + +@return The new reference counter value. +*/ +TInt CSqlCompactEntry::AddRef() + { + SQLCOMPACTENTRY_INVARIANT(); + return ++iRefCounter; + } + +/** +Decrements the entry reference counter. +If the counter reaches zero, the CSqlCompactEntry instance will be destroyed. + +@return The new reference counter value. +*/ +TInt CSqlCompactEntry::Release() + { + SQLCOMPACTENTRY_INVARIANT(); + TInt rc = --iRefCounter; + if(rc == 0) + { + delete this; + } + return rc; + } + +/** +SQLite calls this function when the free pages count reaches the threshold. +The callback must have been registered at the moment of the database connection creation in order this to happen. +The callback implementation will schedule a background compaction (kicking-off the timer). +If a background compaction has already been scheduled, the implementation will only update the iPageCount data +meber value. + +@param aThis A pointer to the CSqlCompactEntry object for which the free page count reached or is above the threshold. +@param aFreePageCount Free pages count. + +@panic SqlDb 4 In _DEBUG mode. NULL aThis parameter. +@panic SqlDb 4 In _DEBUG mode. aFreePageCount is negative or zero. +*/ +/* static */ void CSqlCompactEntry::FreePageCallback(void* aThis, TInt aFreePageCount) + { + __SQLASSERT(aThis != NULL, ESqlPanicBadArgument); + __SQLASSERT(aFreePageCount > 0, ESqlPanicBadArgument); + + CSqlCompactEntry& entry = *(static_cast (aThis)); + if(entry.iFreePageCallbackDisabled) + {//The callback is disabled during the background compaction step. + //The server is single-threaded, so no other client can activate the callback. + //During the background compaction step the callback can be activated only by the completion of the background + //compaction in which case if "entry.iPageCount" is bigger than the threshold, the page counter will be set from here + //and set second time from CSqlCompactEntry::Compact() - the counter value will be reduced twice. + return; + } + + entry.iPageCount = aFreePageCount; + if(entry.iState == CSqlCompactEntry::EInactive) + { + entry.iState = CSqlCompactEntry::EInProgress; + entry.iTimer.Queue(entry); + } + } + +/** +Initializes the CSqlCompactEntry data members with their default values. + +@param aSettings Background compaction settings/thresholds +*/ +CSqlCompactEntry::CSqlCompactEntry(const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer) : + iSettings(aSettings), + iTimer(aTimer), + iRefCounter(1), + iState(CSqlCompactEntry::EInactive) + { + } + +/** +Initializes the created CSqlCompactEntry instance. +Schedules a background compaction if the free pages count is above the threshold. + +@param aFullName The full database name, including the path. +@param aConnFactoryL MSqlCompactConn factory function. + +@panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter) +@panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL. +@panic SqlDb 7 In _DEBUG mode. The CSqlCompactEntry instance has been initialized already. +*/ +void CSqlCompactEntry::ConstructL(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL) + { + __SQLASSERT(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, ESqlPanicBadArgument); + __SQLASSERT(aConnFactoryL != NULL, ESqlPanicBadArgument); + __SQLASSERT(!iConnection, ESqlPanicInternalError); + + __SQLLEAVE_IF_ERROR(iFullName.Create(aFullName)); + + //The second parameter of TSqlFreePageCallback's constructor is expected the be threshold in pages. + //But the connection is not established yet and the page size is not known. Hence the threshold parameter + //value is initialized with the threshold in Kbs. The connection construction is expected to convert + //the threshold from Kbs to pages when the connection with the database is established. + TSqlFreePageCallback callback(this, iSettings.iFreePageThresholdKb, &CSqlCompactEntry::FreePageCallback); + iConnection = (*aConnFactoryL)(aFullName, callback); + __SQLASSERT(iConnection != NULL, ESqlPanicInternalError); + + //"callback.iThreshold > 0" is an indication that the background compaction should be kicked-off + if(callback.iThreshold > 0) + { + //Kick-off the compaction timer, if the number of the free pages is above the threshold. + CSqlCompactEntry::FreePageCallback(this, callback.iThreshold); + } + + SQLCOMPACTENTRY_INVARIANT(); + } + +/** +Performs a compaction step on the database. +If the number of the free pages is bigger than the number of pages removed in one compaction step, +the function will reschedule itself for another compaction step. + +@return KErrNoMemory, an out of memory condition has occurred; + Note that the function may also return some other database specific + errors categorised as ESqlDbError, and other system-wide error codes. + +@panic SqlDb 7 In _DEBUG mode. iPageCount <= 0 - no free pages to be processed. +@panic SqlDb 7 In _DEBUG mode. iState != CSqlCompactEntry::EInProgress. +*/ +TInt CSqlCompactEntry::Compact() + { + //RDebug::Print(_L("++ CSqlCompactEntry::Compact() ++\r\n")); + SQLCOMPACTENTRY_INVARIANT(); + __SQLASSERT(iPageCount > 0, ESqlPanicInternalError); + __SQLASSERT(iState == CSqlCompactEntry::EInProgress, ESqlPanicInternalError); + TInt processedPageCount = 0; + iFreePageCallbackDisabled = ETrue; + TInt err = Connection().Compact(iPageCount, processedPageCount, iSettings.iStepLength); + iFreePageCallbackDisabled = EFalse; + __SQLASSERT(processedPageCount >= 0, ESqlPanicInternalError); + if(err == KErrNone) + { + if(processedPageCount > 0) + { + iPageCount -= processedPageCount; + } + else + { + iPageCount = 0; + } + __SQLASSERT(iPageCount >= 0, ESqlPanicInternalError); + } + if(iPageCount <= 0) + {//No more pages to compact. Stop the compacting, move to EInactive state, remove from the timer queue. + ResetState(); + iTimer.DeQueue(*this); + } + SQLCOMPACTENTRY_INVARIANT(); + return err; + } + +/** +Returns the full database name, including the path. + +@return Full database name. +*/ +const TDesC& CSqlCompactEntry::FullName() const + { + SQLCOMPACTENTRY_INVARIANT(); + return iFullName; + } + +/** +Resets the CSqlCompactEntry internal state. +That means - (1) no scheduled compaction step and (2) no pending free pages to be removed. +*/ +void CSqlCompactEntry::ResetState() + { + SQLCOMPACTENTRY_INVARIANT(); + iState = CSqlCompactEntry::EInactive; + iPageCount = 0; + SQLCOMPACTENTRY_INVARIANT(); + } + +/** +Returns a reference to the MSqlCompactConn interface. +@return A reference to the MSqlCompactConn interface. + +@panic SqlDb 7 NULL MSqlCompactConn interface. +*/ +MSqlCompactConn& CSqlCompactEntry::Connection() + { + SQLCOMPACTENTRY_INVARIANT(); + __SQLASSERT_ALWAYS(iConnection != NULL, ESqlPanicInternalError); + return *iConnection; + } + +#ifdef _DEBUG +/** +CSqlCompactEntry invariant. +*/ +void CSqlCompactEntry::Invariant() const + { + __SQLASSERT(iFullName.Length() > 0 && iFullName.Length() <= KMaxFileName, ESqlPanicInternalError); + __SQLASSERT(iConnection != NULL, ESqlPanicInternalError); + __SQLASSERT(iRefCounter > 0, ESqlPanicInternalError); + __SQLASSERT(iState == CSqlCompactEntry::EInactive || iState == CSqlCompactEntry::EInProgress, ESqlPanicInternalError); + __SQLASSERT(iPageCount >= 0, ESqlPanicInternalError); + iSettings.Invariant(); + } +#endif//_DEBUG