os/persistentdata/persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,293 @@
     1.4 +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include <e32debug.h>
    1.20 +#include <hal.h>
    1.21 +#include <sqldb.h>
    1.22 +#include "SqlAssert.h"
    1.23 +#include "SqlCompactEntry.h"
    1.24 +#include "SqlCompactTimer.h"
    1.25 +#include "SqliteSymbian.h"		//TSqlFreePageCallback
    1.26 +#include "OstTraceDefinitions.h"
    1.27 +#ifdef OST_TRACE_COMPILER_IN_USE
    1.28 +#include "SqlCompactEntryTraces.h"
    1.29 +#endif
    1.30 +#include "SqlTraceDef.h"
    1.31 +
    1.32 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    1.33 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    1.34 +
    1.35 +/**
    1.36 +Creates a new CSqlCompactEntry instance.
    1.37 +
    1.38 +@param aFullName The full database name, including the path.
    1.39 +@param aConnFactoryL MSqlCompactConn factory function.
    1.40 +@param aSettings Background compaction settings/thresholds
    1.41 +@param aTimer The background compaction timer object
    1.42 +
    1.43 +When the free pages threshold is reached, the background compaction 
    1.44 +for this entry will be kicked-off.
    1.45 +
    1.46 +@return A pointer to the created CSqlCompactEntry instance
    1.47 +
    1.48 +@leave KErrNoMemory, an out of memory condition has occurred;
    1.49 +                     Note that the function may also leave with some other database specific 
    1.50 +                     errors categorised as ESqlDbError, and other system-wide error codes.
    1.51 +
    1.52 +@panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter)
    1.53 +@panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL.
    1.54 +*/
    1.55 +CSqlCompactEntry* CSqlCompactEntry::NewLC(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL, 
    1.56 +										  const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer)
    1.57 +	{
    1.58 +	SQL_TRACE_COMPACT(OstTraceExt1(TRACE_INTERNALS, CSQLCOMPACTENTRY_NEWLC_ENTRY, "Entry;0;CSqlCompactEntry::NewLC;aFullName=%S", __SQLPRNSTR(aFullName)));
    1.59 +	__ASSERT_DEBUG(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, __SQLPANIC2(ESqlPanicBadArgument)); 
    1.60 +	__ASSERT_DEBUG(aConnFactoryL != NULL, __SQLPANIC2(ESqlPanicBadArgument));
    1.61 +	CSqlCompactEntry* self = new (ELeave) CSqlCompactEntry(aSettings, aTimer);
    1.62 +	CleanupStack::PushL(self);
    1.63 +	self->ConstructL(aFullName, aConnFactoryL);
    1.64 +	SQL_TRACE_COMPACT(OstTrace1(TRACE_INTERNALS, CSQLCOMPACTENTRY_NEWLC_EXIT, "Exit;0x%X;CSqlCompactEntry::NewLC", (TUint)self));
    1.65 +	return self;
    1.66 +	}
    1.67 +
    1.68 +/**
    1.69 +Destroys the CSqlCompactEntry instance. The database connection will be closed.
    1.70 +*/
    1.71 +CSqlCompactEntry::~CSqlCompactEntry()
    1.72 +	{
    1.73 +	SQL_TRACE_COMPACT(OstTraceExt3(TRACE_INTERNALS, CSQLCOMPACTENTRY_CSQLCOMPACTENTRY2, "0x%X;CSqlCompactEntry::~CSqlCompactEntry;iState=%d;iPageCount=%d", (TUint)this, (TInt)iState, iPageCount));
    1.74 +	if(iState == CSqlCompactEntry::EInProgress)
    1.75 +		{
    1.76 +		iTimer.DeQueue(*this);
    1.77 +		}
    1.78 +	if(iConnection)
    1.79 +		{
    1.80 +		iConnection->Release();	
    1.81 +		}
    1.82 +	iFullName.Close();
    1.83 +	}
    1.84 +
    1.85 +/**
    1.86 +Increments the entry reference counter.
    1.87 +
    1.88 +@return The new reference counter value.
    1.89 +*/
    1.90 +TInt CSqlCompactEntry::AddRef()
    1.91 +	{
    1.92 +	SQL_TRACE_COMPACT(OstTraceExt4(TRACE_INTERNALS, CSQLCOMPACTENTRY_ADDREF, "0x%X;CSqlCompactEntry::AddRef;iState=%d;iPageCount=%d;iRefCounter=%d", (TUint)this, (TInt)iState, iPageCount, iRefCounter));
    1.93 +	SQLCOMPACTENTRY_INVARIANT();
    1.94 +	return ++iRefCounter;
    1.95 +	}
    1.96 +
    1.97 +/**
    1.98 +Decrements the entry reference counter.
    1.99 +If the counter reaches zero, the CSqlCompactEntry instance will be destroyed.
   1.100 +
   1.101 +@return The new reference counter value.
   1.102 +*/
   1.103 +TInt CSqlCompactEntry::Release()
   1.104 +	{
   1.105 +	SQL_TRACE_COMPACT(OstTraceExt4(TRACE_INTERNALS, CSQLCOMPACTENTRY_RELEASE, "0x%X;CSqlCompactEntry::Release;iState=%d;iPageCount=%d;iRefCounter=%d", (TUint)this, (TInt)iState, iPageCount, iRefCounter));
   1.106 +	SQLCOMPACTENTRY_INVARIANT();
   1.107 +	TInt rc = --iRefCounter;
   1.108 +	if(rc == 0)
   1.109 +		{
   1.110 +		delete this;	
   1.111 +		}
   1.112 +	return rc;
   1.113 +	}
   1.114 +
   1.115 +/**
   1.116 +SQLite calls this function when the free pages count reaches the threshold.
   1.117 +The callback must have been registered at the moment of the database connection creation in order this to happen.
   1.118 +The callback implementation will schedule a background compaction (kicking-off the timer).
   1.119 +If a background compaction has already been scheduled, the implementation will only update the iPageCount data
   1.120 +meber value.
   1.121 +
   1.122 +@param aThis A pointer to the CSqlCompactEntry object for which the free page count reached or is above the threshold.
   1.123 +@param aFreePageCount Free pages count.
   1.124 +
   1.125 +@panic SqlDb 4 In _DEBUG mode. NULL aThis parameter.
   1.126 +@panic SqlDb 4 In _DEBUG mode. aFreePageCount is negative or zero.
   1.127 +*/
   1.128 +/* static */ void CSqlCompactEntry::FreePageCallback(void* aThis, TInt aFreePageCount)
   1.129 +	{
   1.130 +	__ASSERT_DEBUG(aThis != NULL, __SQLPANIC2(ESqlPanicBadArgument)); 
   1.131 +	__ASSERT_DEBUG(aFreePageCount > 0, __SQLPANIC2(ESqlPanicBadArgument)); 
   1.132 +	
   1.133 +	CSqlCompactEntry& entry = *(static_cast <CSqlCompactEntry*> (aThis));
   1.134 +	SQL_TRACE_COMPACT(OstTraceExt3(TRACE_INTERNALS, CSQLCOMPACTENTRY_FREEPAGECALLBACK, "0x%X;CSqlCompactEntry::FreePageCallback;aFreePageCount=%d;iState=%d", (TUint)aThis, aFreePageCount, (TInt)entry.iState));
   1.135 +	if(entry.iFreePageCallbackDisabled)
   1.136 +		{//The callback is disabled during the background compaction step.
   1.137 +		 //The server is single-threaded, so no other client can activate the callback.
   1.138 +		 //During the background compaction step the callback can be activated only by the completion of the background 
   1.139 +		 //compaction in which case if "entry.iPageCount" is bigger than the threshold, the page counter will be set from here
   1.140 +		 //and set second time from CSqlCompactEntry::Compact() - the counter value will be reduced twice.
   1.141 +		return;	
   1.142 +		}
   1.143 +	
   1.144 +	entry.iPageCount = aFreePageCount;
   1.145 +	if(entry.iState == CSqlCompactEntry::EInactive)
   1.146 +		{
   1.147 +		entry.iState = CSqlCompactEntry::EInProgress;
   1.148 +		entry.iTimer.Queue(entry);
   1.149 +		}
   1.150 +	}
   1.151 +
   1.152 +/**
   1.153 +Initializes the CSqlCompactEntry data members with their default values.
   1.154 +
   1.155 +@param aSettings Background compaction settings/thresholds
   1.156 +*/
   1.157 +CSqlCompactEntry::CSqlCompactEntry(const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer) :
   1.158 +	iSettings(aSettings),
   1.159 +	iTimer(aTimer),
   1.160 +	iRefCounter(1),
   1.161 +	iState(CSqlCompactEntry::EInactive)
   1.162 +	{
   1.163 +	}
   1.164 +
   1.165 +/**
   1.166 +Initializes the created CSqlCompactEntry instance.
   1.167 +Schedules a background compaction if the free pages count is above the threshold.
   1.168 +
   1.169 +@param aFullName The full database name, including the path.
   1.170 +@param aConnFactoryL MSqlCompactConn factory function.
   1.171 +
   1.172 +@panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter)
   1.173 +@panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL.
   1.174 +@panic SqlDb 7 In _DEBUG mode. The CSqlCompactEntry instance has been initialized already.
   1.175 +*/
   1.176 +void CSqlCompactEntry::ConstructL(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL)
   1.177 +	{
   1.178 +	__ASSERT_DEBUG(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, __SQLPANIC(ESqlPanicBadArgument)); 
   1.179 +	__ASSERT_DEBUG(aConnFactoryL != NULL, __SQLPANIC(ESqlPanicBadArgument));
   1.180 +	__ASSERT_DEBUG(!iConnection, __SQLPANIC(ESqlPanicInternalError));
   1.181 +	
   1.182 +	__SQLLEAVE_IF_ERROR(iFullName.Create(aFullName));
   1.183 +
   1.184 +	//The second parameter of TSqlFreePageCallback's constructor is expected the be threshold in pages.
   1.185 +	//But the connection is not established yet and the page size is not known. Hence the threshold parameter
   1.186 +	//value is initialized with the threshold in Kbs. The connection construction is expected to convert
   1.187 +	//the threshold from Kbs to pages when the connection with the database is established.
   1.188 +	TSqlFreePageCallback callback(this, iSettings.iFreePageThresholdKb, &CSqlCompactEntry::FreePageCallback);
   1.189 +	iConnection = (*aConnFactoryL)(aFullName, callback);
   1.190 +	__ASSERT_DEBUG(iConnection != NULL, __SQLPANIC(ESqlPanicInternalError));
   1.191 +	
   1.192 +	//"callback.iThreshold > 0" is an indication that the background compaction should be kicked-off
   1.193 +	if(callback.iThreshold > 0) 
   1.194 +		{
   1.195 +		//Kick-off the compaction timer, if the number of the free pages is above the threshold.
   1.196 +		CSqlCompactEntry::FreePageCallback(this, callback.iThreshold);
   1.197 +		}
   1.198 +		
   1.199 +	SQLCOMPACTENTRY_INVARIANT();
   1.200 +	}
   1.201 +
   1.202 +/**
   1.203 +Performs a compaction step on the database.
   1.204 +If the number of the free pages is bigger than the number of pages removed in one compaction step,
   1.205 +the function will reschedule itself for another compaction step.
   1.206 +If the database file is corrupted, then the function will remove the database entry from the timer queue - 
   1.207 +the database won't be compacted anymore.
   1.208 +
   1.209 +@return KErrNoMemory, an out of memory condition has occurred;
   1.210 +                      Note that the function may also return some other database specific 
   1.211 +                      errors categorised as ESqlDbError, and other system-wide error codes.
   1.212 +
   1.213 +@panic SqlDb 7 In _DEBUG mode. iPageCount <= 0 - no free pages to be processed.
   1.214 +@panic SqlDb 7 In _DEBUG mode. iState != CSqlCompactEntry::EInProgress.
   1.215 +*/
   1.216 +TInt CSqlCompactEntry::Compact()
   1.217 +	{
   1.218 +	SQL_TRACE_COMPACT(OstTraceExt3(TRACE_INTERNALS, CSQLCOMPACTENTRY_COMPACT_ENTRY, "Entry;0x%X;CSqlCompactEntry::Compact;aFreePageCount=%d;iState=%d", (TUint)this, iPageCount, (TInt)iState));
   1.219 +	SQLCOMPACTENTRY_INVARIANT();
   1.220 +	__ASSERT_DEBUG(iPageCount > 0, __SQLPANIC(ESqlPanicInternalError));
   1.221 +	__ASSERT_DEBUG(iState == CSqlCompactEntry::EInProgress, __SQLPANIC(ESqlPanicInternalError));
   1.222 +	TInt processedPageCount = 0;
   1.223 +	iFreePageCallbackDisabled = ETrue;
   1.224 +	TInt err = Connection().Compact(iPageCount, processedPageCount, iSettings.iStepLength);
   1.225 +	iFreePageCallbackDisabled = EFalse;
   1.226 +	__ASSERT_DEBUG(processedPageCount >= 0, __SQLPANIC(ESqlPanicInternalError));
   1.227 +	if(err == KErrNone)
   1.228 +		{
   1.229 +		iPageCount -= processedPageCount;
   1.230 +        if(processedPageCount == 0)
   1.231 +            {
   1.232 +            iPageCount = 0;
   1.233 +            }
   1.234 +		__ASSERT_DEBUG(iPageCount >= 0, __SQLPANIC(ESqlPanicInternalError));
   1.235 +		}
   1.236 +	TBool stopCompaction = err == KSqlErrCorrupt || err == KSqlErrNotDb || err == KErrCorrupt || err == KErrDisMounted;
   1.237 +	if(iPageCount <= 0 || stopCompaction)
   1.238 +		{//No more pages to compact or the file is corrupted . Stop the compacting, move to EInactive state, remove from the timer queue.
   1.239 +		ResetState();
   1.240 +		iTimer.DeQueue(*this);
   1.241 +		}
   1.242 +	SQL_TRACE_COMPACT(OstTraceExt4(TRACE_INTERNALS, CSQLCOMPACTENTRY_COMPACT_EXIT, "Exit;0x%X;CSqlCompactEntry::Compact;iPageCount=%d;iState=%d;err=%d", (TUint)this, iPageCount, (TInt)iState, err));
   1.243 +	SQLCOMPACTENTRY_INVARIANT();
   1.244 +	return err;
   1.245 +	}
   1.246 +
   1.247 +/**
   1.248 +Returns the full database name, including the path.
   1.249 +
   1.250 +@return Full database name.
   1.251 +*/
   1.252 +const TDesC& CSqlCompactEntry::FullName() const
   1.253 +	{
   1.254 +	SQLCOMPACTENTRY_INVARIANT();
   1.255 +	return iFullName;
   1.256 +	}
   1.257 +
   1.258 +/**
   1.259 +Resets the CSqlCompactEntry internal state.
   1.260 +That means - (1) no scheduled compaction step and (2) no pending free pages to be removed.
   1.261 +*/
   1.262 +void CSqlCompactEntry::ResetState()
   1.263 +	{
   1.264 +	SQLCOMPACTENTRY_INVARIANT();
   1.265 +	iState = CSqlCompactEntry::EInactive;
   1.266 +	iPageCount = 0;
   1.267 +	SQLCOMPACTENTRY_INVARIANT();
   1.268 +	}
   1.269 +
   1.270 +/**
   1.271 +Returns a reference to the MSqlCompactConn interface.
   1.272 +@return A reference to the MSqlCompactConn interface.
   1.273 +
   1.274 +@panic SqlDb 7 NULL MSqlCompactConn interface.
   1.275 +*/
   1.276 +MSqlCompactConn& CSqlCompactEntry::Connection()
   1.277 +	{
   1.278 +	SQLCOMPACTENTRY_INVARIANT();
   1.279 +	__ASSERT_ALWAYS(iConnection != NULL, __SQLPANIC(ESqlPanicInternalError));
   1.280 +	return *iConnection;
   1.281 +	}
   1.282 +
   1.283 +#ifdef _DEBUG
   1.284 +/**
   1.285 +CSqlCompactEntry invariant.
   1.286 +*/
   1.287 +void CSqlCompactEntry::Invariant() const
   1.288 +	{
   1.289 +	__ASSERT_DEBUG(iFullName.Length() > 0 && iFullName.Length() <= KMaxFileName, __SQLPANIC(ESqlPanicInternalError)); 
   1.290 +	__ASSERT_DEBUG(iConnection != NULL, __SQLPANIC(ESqlPanicInternalError));
   1.291 +	__ASSERT_DEBUG(iRefCounter > 0, __SQLPANIC(ESqlPanicInternalError));
   1.292 +	__ASSERT_DEBUG(iState == CSqlCompactEntry::EInactive || iState == CSqlCompactEntry::EInProgress, __SQLPANIC(ESqlPanicInternalError));
   1.293 +	__ASSERT_DEBUG(iPageCount >= 0, __SQLPANIC(ESqlPanicInternalError));
   1.294 +	iSettings.Invariant();
   1.295 +	}
   1.296 +#endif//_DEBUG