--- /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 <e32debug.h>
+#include <hal.h>
+#include <sqldb.h>
+#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 <CSqlCompactEntry*> (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