diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/SRC/Common/SqlBufFlat.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/sql/SRC/Common/SqlBufFlat.h Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,264 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#ifndef __SQLBUFFLAT_H__ +#define __SQLBUFFLAT_H__ + +#include +#include "SqlPanic.h" + +//Forward declarations +class TSqlBufRIterator; +class CSqlSecurityPolicy; +class TSqlSecurityPolicyIterator; + +#ifdef _DEBUG +const TUint64 KSqlBufFlatMagicValue = 0xAA11BB44221199EEULL;//TInt64 for 8-byte alignment +#define SQLFLATBUF_INVARIANT() Invariant() +#else +#define SQLFLATBUF_INVARIANT() void(0) +#endif + +/** +RSqlBufFlat class manages a flat memory buffer with fixed elements count. +Each element (or field) of the flat buffer has a type and variable length data and is accessible using an +index. The data may be NULL. +The RSqlBufFlat objects are used for sending/receiving data between client dlls and servers, +because once the buffer filled, a pointer to the flat buffer data can be used to send the whole buffer in a single +IPC call, which is more effective than using a stream like transfer. + +RSqlBufFlat public functions are not very convenient for storing/retrieving values based on the column type +and there are two additional classes which may be used instead of working with the flat buffer directly: +TSqlBufRIterator and TSqlBufWIterator. + +The physical structure of the flat buffer is: +--------------------------- +| SysData | Header | Data | +--------------------------- +- "SysData" has fixed length and contains fields with about the buffer used size, elements count, header size; +- "Header" has fixed length, which depends of the number of elements and contains cells, one per element. + Each cell contains information about: element type, element data length, the start position of the + element data in the flat buffer, "present"/"not present" flag. "Not present" means that no memory + is reserved for the element data, but the buffer "knows" what is the element type and element data length; + (In the current design there is no "Present"/"Not present flag". If the data position is 0, that indicates + the element is "Not present"). See RSqlBufFlat::TCell comments for details. +- "Data" Is the dynamic part of the buffer which may grow during the operations with the flat buffer (setting + element data); + +"Present"/"Not present" attribute has a key role in the large data transfers between the client and the server. +In order to optimize memory usage, usually the client specifies what can be the max field size. The server +knows that and when it fills a particular flat buffer, which has to be sent to the client, it puts in the +flat buffer only the pieces of data whose size is less than the specified "large data" size. Any data piece whose +size is larger will be set as "Not present" in the flat buffer. The "Not present" field will have all the +attributes, like type and size, but won't have any data or any allocated flat buffer memory. +So the client, when it receives the flat buffer, will know the field type and size and if it wants to get the field data, +will have to make an additional call to the server. + +Note that the fields in the buffer are 8-byte aligned. + +Typical examples how the buffer can be used: + +Case 1 - a dll client wants to receive from the server a flat buffer data. + +@code +RSqlBufFlat bufFlat; +bufFlat.SetCount(N); //N is the field count +.... +bufFlat.Reset(); //Clears the content of the buffer without shrinking it. +ipcArgs.Set(0, bufFlat.MaxSize()); //Tell the server what is the flat buffer max size +ipcArgs.Set(1, &bufFlat.BufPtr()); +TInt rc = session.SendReceive(funcNum, ipcArgs); +if(rc > KSqlClientBufOverflowCode) + { //the client buffer is not big enough and has to be resized + rc = bufFlat.ReAlloc(err - KSqlClientBufOverflowCode); + if(rc != KErrNone) + { + return rc; + } + ipcArgs.Set(0, bufFlat.MaxSize()); + ipcArgs.Set(1, &bufFlat.BufPtr()); + rc = session.SendReceive(funcNum, ipcArgs); + } +@endcode + +Case 2 - a dll client wants to send to the server a flat buffer data. + +@code +RSqlBufFlat bufFlat; +bufFlat.SetCount(N); //N is the field count +.... +TPtrC8 ptr(bufFlat.BufDes()); +TInt err = session.SendReceive(funcNum, TIpcArgs(ptr.Length(), &ptr)); +@endcode + +Case 3 - the server wants to return to the client a flat buffer data. +@code +RSqlBufFlat bufFlat; +bufFlat.SetCount(N); //N is the field count +.... +TInt maxCliBufSize = msg.Int0(); //The max size of the client buffer +if(maxCliBufSize < bufFlat.Size()) + { + return bufFlat.Size() + KSqlClientBufOverflowCode;//Tell the client that its buffer is too small + } +msg.WriteL(1, bufFlat.BufDes()); +@endcode + +Case 4 - the server wants to receive from the client a flat buffer data. +@code +RSqlBufFlat bufFlat; +bufFlat.SetCount(N); //N is the field count +.... +TInt cliBufFlatLen = aMessage.Int0(); +TInt err = bufFlat.ReAlloc(cliBufFlatLen); //Reallocate memory for the flat buffer +if(err != KErrNone) + { + return err; + } +msg.ReadL(1, bufFlat.BufPtr()); +@endcode + +Case 5 - the server (or the client) wants to fill the flat buffer with some data. +@code +RSqlBufFlat bufFlat; +bufFlat.SetCount(N); //N is the field count +.... +TInt err = flatBuf.SetCount(M); //If the field count has to be changed to M +if(err != KErrNone) + { + return err; + } +//use the TSqlBufWIterator iterator to fill the buffer +@endcode + +@see TSqlBufRIterator +@see TSqlBufWIterator +@see RSqlBufFlat::TCell +@see RSqlBufFlat::TBufFlat + +@internalComponent +*/ +class RSqlBufFlat + { + friend class TSqlBufRIterator; + friend class CSqlSecurityPolicy; + friend class TSqlSecurityPolicyIterator; + +public: + //This enum has to be in the "public" section because it is used by TCell (declared as "private" in RSqlBufFlat) + enum + { + EWidthType = 3, //Bit width of the "Type" field of the header cell + EWidthLen = 29 //Bit width of the "Length" field of the header cell + }; + //This enum has to be in the "public" section because it is used by TCell (declared as "private" in RSqlBufFlat) + enum + { + EMaxType = 1 << EWidthType, //Max allowed flat buffer field type + EMaxLength = 1 << EWidthLen //Max allowed flat buffer field length + }; + + RSqlBufFlat(); + TInt SetCount(TInt aCount); + TInt ReAlloc(TInt aSize); + void ResetAndMinimize(); + void Reset(); + void Close(); + inline TInt Count() const; + inline TInt Size() const; + inline TInt MaxSize() const; + + TInt SetField(TInt aIndex, TInt aType, const void* aData, TInt aDataLength); + + inline const TDesC8& BufDes() const; + inline TPtr8& BufPtr(); + +private: //Data type declarations + /** + TCell represents the structure of header cells. + Each cells contains the following fields: + - Flat buffer field type; + - Flat buffer field length; + - Flat buffer field data position; + = if 0 then the field is "Not present" (no memory is reserved for the field data, the field data is missing); + = if positive - the field data position in the flat buffer (counting from the beginning of the header); + = if negative - the field is "Not present", but memory has been reserved for it; + + RSqlBufFlat class offers fast, indexed access to the header cells. + + @see RSqlBufFlat + */ + struct TCell + { + inline TInt Type() const {return (iBits >> RSqlBufFlat::EWidthLen) & (RSqlBufFlat::EMaxType - 1);} + inline TInt Size() const {return (iBits & (RSqlBufFlat::EMaxLength - 1));} + TUint32 iBits; //element type: EWidthType bits & element length: EWidthLen bits. + TInt32 iPos; //element data position, relative to the beginning of the header. + // Zero if the element is not present. + // Negative if the element is not present but memory is reserved. + }; + + enum {EExpandSize = 256}; //iBuf min expansion size - it must be a power of 2 and + // (EExpandSize % 8) should be 0. + /** + TBufFlat structure represents the "SysData" part of the flat buffer (see RSqlBufFlat comments), beyond which + begins the flat buffer header and "Data" part. + + TBufFlat structure contains information about: + - Flat buffer elements count; + - Flat buffer header size; + - The size of used part of the flat buffer; + + @see RSqlBufFlat + */ + struct TBufFlat + { + TInt iCount; //element count + TInt iHeaderSize; //buffer header size + TInt iSize; //used buffer size + TInt iReserved; //maintains TBufFlat 8-byte aligned + }; + +private: //Method declarations + void DoInit(); + TInt DoReAlloc(TInt aSize); + inline TInt Available() const; + void DoSet(TInt aIndex, TInt aType, const void* aData, TInt aDataLength); + TInt Reserve(TInt aLength); + void Invariant() const; + inline const TCell* Header() const; + inline TCell* Header(); + inline TInt SysDataSize() const; + +private: //Data declarations + // IPC data + TBufFlat* iBuf; + // non-IPC data + TInt iMaxSize; //max buffer size (allocated memory), not part of RSqlBufFlat data (IPC - sent/received). + //iMaxSize can't be part of the IPC data, because it may be overwritten, which leads to + //"hard to detect" problems. For example: + // - client sends to the server in/out flat buffer with max size 256 bytes (allocated); + // - the server has a flat buffer which max size is 512, but the used size is 200; + // - the client flat buffer has enough space for those 200 bytes, so the server will + // copy its flat buffer content to the client flat buffer. The client's flat buffer + // iMaxSize data member will lose its original value (256) and will have new value assigned - + // 512. But the client flat buffer does not have 512 bytes allocated! + mutable TPtrC8 iBufPtrC; //it is set to point to iBuf. Not part of RSqlBufFlat data (IPC - sent/received) + mutable TPtr8 iBufPtr; //it is set to point to iBuf. Not part of RSqlBufFlat data (IPC - sent/received) + }; + +#include "SqlBufFlat.inl" + +#endif//__SQLBUFFLAT_H__