persistentstorage/sql/SRC/Common/SqlBufFlat.cpp
changeset 0 08ec8eefde2f
child 23 26645d81f48d
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2006-2009 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 "SqlUtil.h"
       
    17 #include "SqlBufFlat.h"
       
    18 
       
    19 /**
       
    20 Sets the flat buffer pointer to NULL
       
    21 */
       
    22 RSqlBufFlat::RSqlBufFlat() :
       
    23 	iBuf(NULL),
       
    24 	iMaxSize(0),
       
    25 	iBufPtr(NULL, 0)
       
    26 	{
       
    27 	}
       
    28 
       
    29 /**
       
    30 "Resource acquisiton" method.
       
    31 Sets the elements count of a new or already existing flat buffer.
       
    32 
       
    33 The occupied memory won't be freed (in case of buffer resizing).
       
    34 The buffer content is not preserved (in case of buffer resizing).
       
    35 
       
    36 All elements set to have:
       
    37 - invalid type;
       
    38 - zero length;
       
    39 - zero data position;
       
    40 
       
    41 @param aCount Desired flat buffer elements count
       
    42 
       
    43 @return KErrNone, The operation has completed successfully;
       
    44 		KErrNoMemory, Out of memory condition has occured.
       
    45 */
       
    46 TInt RSqlBufFlat::SetCount(TInt aCount)
       
    47 	{
       
    48 	__SQLASSERT(aCount >= 0, ESqlPanicBadArgument);
       
    49 	TInt headerSize = sizeof(RSqlBufFlat::TCell) * aCount;
       
    50 	TInt newSize = headerSize + sizeof(RSqlBufFlat::TBufFlat);
       
    51 	if(DoReAlloc(newSize) != KErrNone)
       
    52 		{
       
    53 		return KErrNoMemory;	
       
    54 		}
       
    55 	TBufFlat& buf = *iBuf;
       
    56 	buf.iCount = aCount;
       
    57 	buf.iHeaderSize = headerSize;
       
    58 	buf.iSize = newSize;
       
    59 	buf.iReserved = 0;
       
    60 	DoInit();
       
    61 	SQLFLATBUF_INVARIANT();
       
    62 	return KErrNone;	
       
    63 	}
       
    64 
       
    65 /**
       
    66 Reallocates the amount of the occupied by the flat buffer memory.
       
    67 The operation preserves the content of the flat buffer.
       
    68 Note: if the new size is less or equal to the max size of the buffer,
       
    69 	  no memory will be allocated.
       
    70 
       
    71 @param aSize Desired flat buffer size in bytes
       
    72 
       
    73 @return KErrNone, The operation has completed successfully;
       
    74 		KErrNoMemory, Out of memory condition has occured.
       
    75 */
       
    76 TInt RSqlBufFlat::ReAlloc(TInt aSize)
       
    77 	{
       
    78 	SQLFLATBUF_INVARIANT();
       
    79 	TInt err = DoReAlloc(aSize);
       
    80 	SQLFLATBUF_INVARIANT();
       
    81 	return err;
       
    82 	}
       
    83 
       
    84 /**
       
    85 Cleans up the flat buffer content and 
       
    86 frees the occupied memory if the memory is above KBufLimit.
       
    87 The count of elements is preserved.
       
    88 
       
    89 If the buffer size is bigger than KBufLimit,
       
    90 the buffer will be reallocated and the buffer content - not preserved.
       
    91 
       
    92 If the buffer size is less or equal to KBufLimit,
       
    93 no memory will be reallocated and the buffer preserves its content.
       
    94 
       
    95 It is guaranteed that the reallocated buffer will have the same address in the heap 
       
    96 as the original one.
       
    97 */	
       
    98 void RSqlBufFlat::ResetAndMinimize()
       
    99 	{
       
   100 	SQLFLATBUF_INVARIANT();
       
   101 	Reset();
       
   102 #ifdef _DEBUG	
       
   103 	const TInt KBufLimit = Max((TInt)RSqlBufFlat::EExpandSize, SysDataSize());
       
   104 	const TBufFlat* oldBuf = iBuf;
       
   105 #else
       
   106 	const TInt KBufLimit = Max((8 * 1024), SysDataSize());
       
   107 #endif
       
   108 	if(iMaxSize > KBufLimit)
       
   109 		{
       
   110 		iMaxSize = KBufLimit - 1;  //to force the reallocation
       
   111 		(void)DoReAlloc(KBufLimit);//User::ReAlloc() does not fail if the new requested size is less than the current block size
       
   112 		}
       
   113 	__SQLASSERT(oldBuf == iBuf, ESqlPanicInternalError);
       
   114 	SQLFLATBUF_INVARIANT();
       
   115 	}
       
   116 
       
   117 /**
       
   118 Cleans up the flat buffer content but does not free the occupied memory.
       
   119 The count of elements is preserved.
       
   120 
       
   121 All elements set to have:
       
   122 - invalid type;
       
   123 - zero length;
       
   124 - zero data position;
       
   125 
       
   126 The element count is preserved.
       
   127 */
       
   128 void RSqlBufFlat::Reset()
       
   129 	{
       
   130 	SQLFLATBUF_INVARIANT();
       
   131 	iBuf->iSize = SysDataSize();
       
   132 	DoInit();
       
   133 	SQLFLATBUF_INVARIANT();
       
   134 	}
       
   135 
       
   136 /**
       
   137 Closes the flat bufer and frees the allocated memory.
       
   138 */
       
   139 void RSqlBufFlat::Close()
       
   140 	{
       
   141 	User::Free(iBuf);
       
   142 	iBuf = NULL;	
       
   143 	}
       
   144 
       
   145 /**
       
   146 Sets the content of a field.
       
   147 
       
   148 @param aIndex Field index
       
   149 @param aType Field type
       
   150 @param aData Field data, may be NULL
       
   151 @param aDataLength Field data length, may be 0
       
   152 
       
   153 @return KErrNone, The operation has completed successfully;
       
   154 		KErrNoMemory, Out of memory condition has occured.
       
   155 */
       
   156 TInt RSqlBufFlat::SetField(TInt aIndex, TInt aType, const void* aData, TInt aDataLength)
       
   157 	{
       
   158 	SQLFLATBUF_INVARIANT();
       
   159 	__SQLASSERT((TUint)aIndex < iBuf->iCount, ESqlPanicBadArgument);
       
   160 	__SQLASSERT((TUint)aType < RSqlBufFlat::EMaxType, ESqlPanicBadArgument);
       
   161 	__SQLASSERT((TUint)aDataLength < RSqlBufFlat::EMaxLength, ESqlPanicBadArgument);
       
   162 	if(aData)						//field value "present"
       
   163 		{
       
   164 		__SQLASSERT(aDataLength >= 0, ESqlPanicBadArgument);
       
   165 		if(aDataLength > 0)
       
   166 			{
       
   167 			if(Reserve(aDataLength) != KErrNone)
       
   168 				{
       
   169 				return KErrNoMemory;	
       
   170 				}
       
   171 			}
       
   172 		DoSet(aIndex, aType, aData, aDataLength);
       
   173 		}
       
   174 	else if(aDataLength == 0)		//data is NULL, length is 0 - "null" field
       
   175 		{
       
   176 		DoSet(aIndex, aType, NULL, 0);
       
   177 		}
       
   178 	else							//field value "not present"
       
   179 		{
       
   180 		RSqlBufFlat::TCell& cell = *(Header() + aIndex);
       
   181 		cell.iBits = (TUint)(((TUint)aType << RSqlBufFlat::EWidthLen) | (TUint)aDataLength);
       
   182 		cell.iPos = 0;
       
   183 		}
       
   184 	SQLFLATBUF_INVARIANT();
       
   185 	return KErrNone;
       
   186 	}
       
   187 	
       
   188 /**
       
   189 Initialzies the flat buffer header.
       
   190 All field set:
       
   191 - invalid type;
       
   192 - zero length;
       
   193 - "Not present";
       
   194 */	
       
   195 void RSqlBufFlat::DoInit()
       
   196 	{
       
   197 	TBufFlat& buf = *iBuf;
       
   198 	__SQLASSERT(buf.iCount >= 0, ESqlPanicInternalError);
       
   199 	__SQLASSERT(buf.iSize <= iMaxSize, ESqlPanicInternalError);
       
   200 	__SQLASSERT(buf.iHeaderSize == sizeof(RSqlBufFlat::TCell) * buf.iCount, ESqlPanicInternalError);
       
   201 	if(buf.iHeaderSize > 0)
       
   202 		{
       
   203 		Mem::FillZ(Header(), buf.iHeaderSize);
       
   204 		}
       
   205 	}
       
   206 
       
   207 /**
       
   208 Reallocates the amount of the occupied by the flat buffer memory
       
   209 (only in case the requested size is bigger than the buffer size or the buffer does not exist).
       
   210 The operation preserves the content of the flat buffer.
       
   211 
       
   212 @param aSize Desired flat buffer size in bytes.
       
   213 
       
   214 @return KErrNone, The operation has completed successfully;
       
   215 		KErrNoMemory, Out of memory condition has occured.
       
   216 */
       
   217 TInt RSqlBufFlat::DoReAlloc(TInt aSize)
       
   218 	{
       
   219 	if(!iBuf || iMaxSize < aSize)
       
   220 		{
       
   221 		//Calculate buffer new size (sometimes allocates more, for example, if
       
   222 		//aSize % RSqlBufFlat::EExpandSize == 0, then one more RSqlBufFlat::EExpandSize page is allocated).
       
   223 		TInt newSize = (aSize / RSqlBufFlat::EExpandSize + 1) * RSqlBufFlat::EExpandSize;
       
   224 		RSqlBufFlat::TBufFlat* newBuf = static_cast <RSqlBufFlat::TBufFlat*> (User::ReAlloc(iBuf, newSize));
       
   225 		if(!newBuf)
       
   226 			{
       
   227 			return KErrNoMemory;	
       
   228 			}
       
   229 		iBuf = newBuf;
       
   230 		iMaxSize = newSize;
       
   231 		}
       
   232 	return KErrNone;
       
   233 	}
       
   234 
       
   235 /**
       
   236 Initialzes a flat buffer field.
       
   237 A memory for the field data has to be allocated before the call.
       
   238 
       
   239 @param aIndex Field index
       
   240 @param aType Field type
       
   241 @param aData Field data, may be NULL
       
   242 @param aDataLength Field data length, may be 0
       
   243 */
       
   244 void RSqlBufFlat::DoSet(TInt aIndex, TInt aType, const void* aData, TInt aDataLength)
       
   245 	{
       
   246 	TBufFlat& buf = *iBuf;
       
   247 	__SQLASSERT((TUint)aDataLength < RSqlBufFlat::EMaxLength, ESqlPanicBadArgument);
       
   248 	__SQLASSERT(aDataLength > 0 ? aData != NULL : ETrue, ESqlPanicBadArgument);
       
   249 	__SQLASSERT(aDataLength <= (iMaxSize - buf.iSize), ESqlPanicInternalError);
       
   250 	__SQLASSERT(::IsAligned8(buf.iSize), ESqlPanicInternalError);
       
   251 	RSqlBufFlat::TCell& cell = *(Header() + aIndex);
       
   252 	cell.iBits = (TUint)(((TUint)aType << RSqlBufFlat::EWidthLen) | (TUint)aDataLength);
       
   253 	cell.iPos = 1;	//not 0, because 0 means "not present"
       
   254 	if(aDataLength > 0)	//for fields with length > 0 set the data and reinitalize cell.iPos
       
   255 		{
       
   256 #ifdef _DEBUG
       
   257 		Mem::Copy(reinterpret_cast <TUint8*> (iBuf) + buf.iSize, &KSqlBufFlatMagicValue, sizeof(KSqlBufFlatMagicValue));
       
   258 		buf.iSize += sizeof(KSqlBufFlatMagicValue);
       
   259 #endif		
       
   260 		cell.iPos = buf.iSize - sizeof(RSqlBufFlat::TBufFlat);
       
   261 		Mem::Copy(reinterpret_cast <TUint8*> (iBuf) + buf.iSize, reinterpret_cast <const TUint8*> (aData), aDataLength);
       
   262 		buf.iSize += ::AlignedLen8(aDataLength);	//align the next field start position
       
   263 				                                  	//it is guaranteed that this "+" operation will not make iSize bigger than
       
   264 				                                   	//iMaxSize, because the memory allocations are 8-byte aligned 
       
   265 				                                   	//(even RSqlBufFlat::EExpandSize aligned)
       
   266 		}
       
   267 	}
       
   268 
       
   269 /**
       
   270 Makes sure that the flat buffer has enough free space for a block of data with "aLength" length.
       
   271 The function may reallocated the buffer if there is not enough space.
       
   272 
       
   273 @param aLength The requested free memory length.
       
   274 
       
   275 @return KErrNone, The operation has completed successfully;
       
   276 		KErrNoMemory, Out of memory condition has occured.
       
   277 */
       
   278 TInt RSqlBufFlat::Reserve(TInt aLength)
       
   279 	{
       
   280 #ifdef _DEBUG
       
   281 	TInt diff = aLength + sizeof(KSqlBufFlatMagicValue) - Available();
       
   282 #else
       
   283 	TInt diff = aLength - Available();
       
   284 #endif		
       
   285 	return diff > 0 ? DoReAlloc(iMaxSize + diff) : KErrNone;
       
   286 	}
       
   287 
       
   288 #ifdef _DEBUG
       
   289 /**
       
   290 Panics in _DEBUG mode if the flat buffer content is inconsistent.
       
   291 */
       
   292 void RSqlBufFlat::Invariant() const
       
   293 	{
       
   294 	__SQLASSERT(iBuf != NULL, ESqlPanicInternalError);
       
   295 	const TBufFlat& buf = *iBuf;
       
   296 	__SQLASSERT(buf.iCount >= 0, ESqlPanicInternalError);
       
   297 	__SQLASSERT(buf.iHeaderSize == sizeof(RSqlBufFlat::TCell) * buf.iCount, ESqlPanicInternalError);
       
   298 	__SQLASSERT(::IsAligned8(buf.iSize), ESqlPanicInternalError);
       
   299 	__SQLASSERT(buf.iSize >= buf.iHeaderSize + sizeof(RSqlBufFlat::TBufFlat), ESqlPanicInternalError);
       
   300 	__SQLASSERT(buf.iSize <= iMaxSize, ESqlPanicInternalError);
       
   301  	__SQLASSERT(buf.iSize <= User::AllocLen(iBuf), ESqlPanicInternalError);	
       
   302 	for(TInt i=0;i<(TInt)buf.iCount;++i)
       
   303 		{
       
   304 		const RSqlBufFlat::TCell& cell = *((reinterpret_cast <const RSqlBufFlat::TCell*> (iBuf + 1)) + i);
       
   305 		__SQLASSERT(cell.Type() < RSqlBufFlat::EMaxType, ESqlPanicInternalError);
       
   306 		if(cell.Size() > 0 && cell.iPos >= buf.iHeaderSize) //only for present fields with length > 0
       
   307 			{
       
   308 			__SQLASSERT((TUint)cell.Size() <= buf.iSize, ESqlPanicInternalError);
       
   309 			__SQLASSERT(cell.iPos < (buf.iSize - sizeof(RSqlBufFlat::TBufFlat)), ESqlPanicInternalError);
       
   310 			TUint64 val = *(TUint64*)(reinterpret_cast <TUint8*> (iBuf) + cell.iPos + sizeof(RSqlBufFlat::TBufFlat) - sizeof(KSqlBufFlatMagicValue));
       
   311 			__SQLASSERT(val == KSqlBufFlatMagicValue, ESqlPanicInternalError);
       
   312 			}
       
   313 		}
       
   314 	}
       
   315 #endif//_DEBUG