os/persistentdata/persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <e32debug.h>
    17 #include <hal.h>
    18 #include <sqldb.h>
    19 #include "SqlAssert.h"
    20 #include "SqlCompactEntry.h"
    21 #include "SqlCompactTimer.h"
    22 #include "SqliteSymbian.h"		//TSqlFreePageCallback
    23 #include "OstTraceDefinitions.h"
    24 #ifdef OST_TRACE_COMPILER_IN_USE
    25 #include "SqlCompactEntryTraces.h"
    26 #endif
    27 #include "SqlTraceDef.h"
    28 
    29 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    30 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    31 
    32 /**
    33 Creates a new CSqlCompactEntry instance.
    34 
    35 @param aFullName The full database name, including the path.
    36 @param aConnFactoryL MSqlCompactConn factory function.
    37 @param aSettings Background compaction settings/thresholds
    38 @param aTimer The background compaction timer object
    39 
    40 When the free pages threshold is reached, the background compaction 
    41 for this entry will be kicked-off.
    42 
    43 @return A pointer to the created CSqlCompactEntry instance
    44 
    45 @leave KErrNoMemory, an out of memory condition has occurred;
    46                      Note that the function may also leave with some other database specific 
    47                      errors categorised as ESqlDbError, and other system-wide error codes.
    48 
    49 @panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter)
    50 @panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL.
    51 */
    52 CSqlCompactEntry* CSqlCompactEntry::NewLC(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL, 
    53 										  const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer)
    54 	{
    55 	SQL_TRACE_COMPACT(OstTraceExt1(TRACE_INTERNALS, CSQLCOMPACTENTRY_NEWLC_ENTRY, "Entry;0;CSqlCompactEntry::NewLC;aFullName=%S", __SQLPRNSTR(aFullName)));
    56 	__ASSERT_DEBUG(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, __SQLPANIC2(ESqlPanicBadArgument)); 
    57 	__ASSERT_DEBUG(aConnFactoryL != NULL, __SQLPANIC2(ESqlPanicBadArgument));
    58 	CSqlCompactEntry* self = new (ELeave) CSqlCompactEntry(aSettings, aTimer);
    59 	CleanupStack::PushL(self);
    60 	self->ConstructL(aFullName, aConnFactoryL);
    61 	SQL_TRACE_COMPACT(OstTrace1(TRACE_INTERNALS, CSQLCOMPACTENTRY_NEWLC_EXIT, "Exit;0x%X;CSqlCompactEntry::NewLC", (TUint)self));
    62 	return self;
    63 	}
    64 
    65 /**
    66 Destroys the CSqlCompactEntry instance. The database connection will be closed.
    67 */
    68 CSqlCompactEntry::~CSqlCompactEntry()
    69 	{
    70 	SQL_TRACE_COMPACT(OstTraceExt3(TRACE_INTERNALS, CSQLCOMPACTENTRY_CSQLCOMPACTENTRY2, "0x%X;CSqlCompactEntry::~CSqlCompactEntry;iState=%d;iPageCount=%d", (TUint)this, (TInt)iState, iPageCount));
    71 	if(iState == CSqlCompactEntry::EInProgress)
    72 		{
    73 		iTimer.DeQueue(*this);
    74 		}
    75 	if(iConnection)
    76 		{
    77 		iConnection->Release();	
    78 		}
    79 	iFullName.Close();
    80 	}
    81 
    82 /**
    83 Increments the entry reference counter.
    84 
    85 @return The new reference counter value.
    86 */
    87 TInt CSqlCompactEntry::AddRef()
    88 	{
    89 	SQL_TRACE_COMPACT(OstTraceExt4(TRACE_INTERNALS, CSQLCOMPACTENTRY_ADDREF, "0x%X;CSqlCompactEntry::AddRef;iState=%d;iPageCount=%d;iRefCounter=%d", (TUint)this, (TInt)iState, iPageCount, iRefCounter));
    90 	SQLCOMPACTENTRY_INVARIANT();
    91 	return ++iRefCounter;
    92 	}
    93 
    94 /**
    95 Decrements the entry reference counter.
    96 If the counter reaches zero, the CSqlCompactEntry instance will be destroyed.
    97 
    98 @return The new reference counter value.
    99 */
   100 TInt CSqlCompactEntry::Release()
   101 	{
   102 	SQL_TRACE_COMPACT(OstTraceExt4(TRACE_INTERNALS, CSQLCOMPACTENTRY_RELEASE, "0x%X;CSqlCompactEntry::Release;iState=%d;iPageCount=%d;iRefCounter=%d", (TUint)this, (TInt)iState, iPageCount, iRefCounter));
   103 	SQLCOMPACTENTRY_INVARIANT();
   104 	TInt rc = --iRefCounter;
   105 	if(rc == 0)
   106 		{
   107 		delete this;	
   108 		}
   109 	return rc;
   110 	}
   111 
   112 /**
   113 SQLite calls this function when the free pages count reaches the threshold.
   114 The callback must have been registered at the moment of the database connection creation in order this to happen.
   115 The callback implementation will schedule a background compaction (kicking-off the timer).
   116 If a background compaction has already been scheduled, the implementation will only update the iPageCount data
   117 meber value.
   118 
   119 @param aThis A pointer to the CSqlCompactEntry object for which the free page count reached or is above the threshold.
   120 @param aFreePageCount Free pages count.
   121 
   122 @panic SqlDb 4 In _DEBUG mode. NULL aThis parameter.
   123 @panic SqlDb 4 In _DEBUG mode. aFreePageCount is negative or zero.
   124 */
   125 /* static */ void CSqlCompactEntry::FreePageCallback(void* aThis, TInt aFreePageCount)
   126 	{
   127 	__ASSERT_DEBUG(aThis != NULL, __SQLPANIC2(ESqlPanicBadArgument)); 
   128 	__ASSERT_DEBUG(aFreePageCount > 0, __SQLPANIC2(ESqlPanicBadArgument)); 
   129 	
   130 	CSqlCompactEntry& entry = *(static_cast <CSqlCompactEntry*> (aThis));
   131 	SQL_TRACE_COMPACT(OstTraceExt3(TRACE_INTERNALS, CSQLCOMPACTENTRY_FREEPAGECALLBACK, "0x%X;CSqlCompactEntry::FreePageCallback;aFreePageCount=%d;iState=%d", (TUint)aThis, aFreePageCount, (TInt)entry.iState));
   132 	if(entry.iFreePageCallbackDisabled)
   133 		{//The callback is disabled during the background compaction step.
   134 		 //The server is single-threaded, so no other client can activate the callback.
   135 		 //During the background compaction step the callback can be activated only by the completion of the background 
   136 		 //compaction in which case if "entry.iPageCount" is bigger than the threshold, the page counter will be set from here
   137 		 //and set second time from CSqlCompactEntry::Compact() - the counter value will be reduced twice.
   138 		return;	
   139 		}
   140 	
   141 	entry.iPageCount = aFreePageCount;
   142 	if(entry.iState == CSqlCompactEntry::EInactive)
   143 		{
   144 		entry.iState = CSqlCompactEntry::EInProgress;
   145 		entry.iTimer.Queue(entry);
   146 		}
   147 	}
   148 
   149 /**
   150 Initializes the CSqlCompactEntry data members with their default values.
   151 
   152 @param aSettings Background compaction settings/thresholds
   153 */
   154 CSqlCompactEntry::CSqlCompactEntry(const TSqlCompactSettings& aSettings, CSqlCompactTimer& aTimer) :
   155 	iSettings(aSettings),
   156 	iTimer(aTimer),
   157 	iRefCounter(1),
   158 	iState(CSqlCompactEntry::EInactive)
   159 	{
   160 	}
   161 
   162 /**
   163 Initializes the created CSqlCompactEntry instance.
   164 Schedules a background compaction if the free pages count is above the threshold.
   165 
   166 @param aFullName The full database name, including the path.
   167 @param aConnFactoryL MSqlCompactConn factory function.
   168 
   169 @panic SqlDb 4 In _DEBUG mode. Too short or too long database name (aFullName parameter)
   170 @panic SqlDb 4 In _DEBUG mode. NULL aConnFactoryL.
   171 @panic SqlDb 7 In _DEBUG mode. The CSqlCompactEntry instance has been initialized already.
   172 */
   173 void CSqlCompactEntry::ConstructL(const TDesC& aFullName, TSqlCompactConnFactoryL aConnFactoryL)
   174 	{
   175 	__ASSERT_DEBUG(aFullName.Length() > 0 && aFullName.Length() <= KMaxFileName, __SQLPANIC(ESqlPanicBadArgument)); 
   176 	__ASSERT_DEBUG(aConnFactoryL != NULL, __SQLPANIC(ESqlPanicBadArgument));
   177 	__ASSERT_DEBUG(!iConnection, __SQLPANIC(ESqlPanicInternalError));
   178 	
   179 	__SQLLEAVE_IF_ERROR(iFullName.Create(aFullName));
   180 
   181 	//The second parameter of TSqlFreePageCallback's constructor is expected the be threshold in pages.
   182 	//But the connection is not established yet and the page size is not known. Hence the threshold parameter
   183 	//value is initialized with the threshold in Kbs. The connection construction is expected to convert
   184 	//the threshold from Kbs to pages when the connection with the database is established.
   185 	TSqlFreePageCallback callback(this, iSettings.iFreePageThresholdKb, &CSqlCompactEntry::FreePageCallback);
   186 	iConnection = (*aConnFactoryL)(aFullName, callback);
   187 	__ASSERT_DEBUG(iConnection != NULL, __SQLPANIC(ESqlPanicInternalError));
   188 	
   189 	//"callback.iThreshold > 0" is an indication that the background compaction should be kicked-off
   190 	if(callback.iThreshold > 0) 
   191 		{
   192 		//Kick-off the compaction timer, if the number of the free pages is above the threshold.
   193 		CSqlCompactEntry::FreePageCallback(this, callback.iThreshold);
   194 		}
   195 		
   196 	SQLCOMPACTENTRY_INVARIANT();
   197 	}
   198 
   199 /**
   200 Performs a compaction step on the database.
   201 If the number of the free pages is bigger than the number of pages removed in one compaction step,
   202 the function will reschedule itself for another compaction step.
   203 If the database file is corrupted, then the function will remove the database entry from the timer queue - 
   204 the database won't be compacted anymore.
   205 
   206 @return KErrNoMemory, an out of memory condition has occurred;
   207                       Note that the function may also return some other database specific 
   208                       errors categorised as ESqlDbError, and other system-wide error codes.
   209 
   210 @panic SqlDb 7 In _DEBUG mode. iPageCount <= 0 - no free pages to be processed.
   211 @panic SqlDb 7 In _DEBUG mode. iState != CSqlCompactEntry::EInProgress.
   212 */
   213 TInt CSqlCompactEntry::Compact()
   214 	{
   215 	SQL_TRACE_COMPACT(OstTraceExt3(TRACE_INTERNALS, CSQLCOMPACTENTRY_COMPACT_ENTRY, "Entry;0x%X;CSqlCompactEntry::Compact;aFreePageCount=%d;iState=%d", (TUint)this, iPageCount, (TInt)iState));
   216 	SQLCOMPACTENTRY_INVARIANT();
   217 	__ASSERT_DEBUG(iPageCount > 0, __SQLPANIC(ESqlPanicInternalError));
   218 	__ASSERT_DEBUG(iState == CSqlCompactEntry::EInProgress, __SQLPANIC(ESqlPanicInternalError));
   219 	TInt processedPageCount = 0;
   220 	iFreePageCallbackDisabled = ETrue;
   221 	TInt err = Connection().Compact(iPageCount, processedPageCount, iSettings.iStepLength);
   222 	iFreePageCallbackDisabled = EFalse;
   223 	__ASSERT_DEBUG(processedPageCount >= 0, __SQLPANIC(ESqlPanicInternalError));
   224 	if(err == KErrNone)
   225 		{
   226 		iPageCount -= processedPageCount;
   227         if(processedPageCount == 0)
   228             {
   229             iPageCount = 0;
   230             }
   231 		__ASSERT_DEBUG(iPageCount >= 0, __SQLPANIC(ESqlPanicInternalError));
   232 		}
   233 	TBool stopCompaction = err == KSqlErrCorrupt || err == KSqlErrNotDb || err == KErrCorrupt || err == KErrDisMounted;
   234 	if(iPageCount <= 0 || stopCompaction)
   235 		{//No more pages to compact or the file is corrupted . Stop the compacting, move to EInactive state, remove from the timer queue.
   236 		ResetState();
   237 		iTimer.DeQueue(*this);
   238 		}
   239 	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));
   240 	SQLCOMPACTENTRY_INVARIANT();
   241 	return err;
   242 	}
   243 
   244 /**
   245 Returns the full database name, including the path.
   246 
   247 @return Full database name.
   248 */
   249 const TDesC& CSqlCompactEntry::FullName() const
   250 	{
   251 	SQLCOMPACTENTRY_INVARIANT();
   252 	return iFullName;
   253 	}
   254 
   255 /**
   256 Resets the CSqlCompactEntry internal state.
   257 That means - (1) no scheduled compaction step and (2) no pending free pages to be removed.
   258 */
   259 void CSqlCompactEntry::ResetState()
   260 	{
   261 	SQLCOMPACTENTRY_INVARIANT();
   262 	iState = CSqlCompactEntry::EInactive;
   263 	iPageCount = 0;
   264 	SQLCOMPACTENTRY_INVARIANT();
   265 	}
   266 
   267 /**
   268 Returns a reference to the MSqlCompactConn interface.
   269 @return A reference to the MSqlCompactConn interface.
   270 
   271 @panic SqlDb 7 NULL MSqlCompactConn interface.
   272 */
   273 MSqlCompactConn& CSqlCompactEntry::Connection()
   274 	{
   275 	SQLCOMPACTENTRY_INVARIANT();
   276 	__ASSERT_ALWAYS(iConnection != NULL, __SQLPANIC(ESqlPanicInternalError));
   277 	return *iConnection;
   278 	}
   279 
   280 #ifdef _DEBUG
   281 /**
   282 CSqlCompactEntry invariant.
   283 */
   284 void CSqlCompactEntry::Invariant() const
   285 	{
   286 	__ASSERT_DEBUG(iFullName.Length() > 0 && iFullName.Length() <= KMaxFileName, __SQLPANIC(ESqlPanicInternalError)); 
   287 	__ASSERT_DEBUG(iConnection != NULL, __SQLPANIC(ESqlPanicInternalError));
   288 	__ASSERT_DEBUG(iRefCounter > 0, __SQLPANIC(ESqlPanicInternalError));
   289 	__ASSERT_DEBUG(iState == CSqlCompactEntry::EInactive || iState == CSqlCompactEntry::EInProgress, __SQLPANIC(ESqlPanicInternalError));
   290 	__ASSERT_DEBUG(iPageCount >= 0, __SQLPANIC(ESqlPanicInternalError));
   291 	iSettings.Invariant();
   292 	}
   293 #endif//_DEBUG