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