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