--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/sdbms/Sd_DriveSpace.cpp Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,424 @@
+// Copyright (c) 2004-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:
+// Reserving/Accessing/Releasing drive space - CDriveSpace, RDriveSpaceCol, CDbsSessDriveSpace
+// classes implementations
+//
+//
+
+#include "U32STD.H"
+#include "Sd_DriveSpace.h"
+
+/**
+That's the amount of the disk space, which will be reserved at the momemnt of creation of
+each CDriveSpace object.
+It should be enough for the most of the "delete" transactions, used by the applications.
+@internalComponent
+*/
+const TInt KReservedDiskSpace = 64 * 1024;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+//CDriveSpace class
+
+/**
+Grants access to the already reserved drive space. The method uses RFs::GetReserveAccess()
+for that. RFs::GetReserveAccess() will be called only once, when iGrantAccessRefCnt is 0 -
+this is a shared file session instance.
+@leave RFs::GetReserveAccess() return values
+@see RFs::GetReserveAccess()
+@panic In debug mode there will be a panic with the line number as an error code if (iGrantAccessRefCnt < 0)
+*/
+void CDriveSpace::GrantAccessL()
+ {
+ __ASSERT(iGrantAccessRefCnt >= 0);
+ //Grant the access only once, there is only one RFs session instance.
+ if(iGrantAccessRefCnt == 0)
+ {
+ __LEAVE_IF_ERROR(iFs.GetReserveAccess(static_cast <TInt> (iDrive)));
+ }
+ ++iGrantAccessRefCnt;
+ }
+
+/**
+Revokes access to the reserved drive space.
+The method calls RFs::ReleaseReserveAccess() only when iGrantAccessRefCnt value reaches 0.
+@see RFs::ReleaseReserveAccess()
+@panic In debug mode there will be a panic with the line number as an error code if (iGrantAccessRefCnt <= 0)
+*/
+void CDriveSpace::ReleaseAccess()
+ {
+ __ASSERT(iGrantAccessRefCnt > 0);
+ if(iGrantAccessRefCnt == 0)
+ {
+ return;
+ }
+ if(--iGrantAccessRefCnt == 0)
+ {
+ //I can't see any reason to bother the caller with errors, when the access to the
+ //reserved space is revoked.
+ (void)iFs.ReleaseReserveAccess(static_cast <TInt> (iDrive));
+ }
+ }
+
+/**
+Standard phase-one factory method for creation of CDriveSpace objects.
+@param aFs File session instance
+@param aDrive Drive number
+@return A pointer to the created CDriveSpace object.
+@leave KErrNoMemory Out of memory
+@leave RFs::ReserveDriveSpace() return values
+@see RFs::ReserveDriveSpace()
+*/
+CDriveSpace* CDriveSpace::NewLC(RFs& aFs, TDriveNumber aDrive)
+ {
+ CDriveSpace* self = new (ELeave) CDriveSpace(aFs, aDrive);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+/**
+@param aFs File session instance
+@param aDrive Drive number
+@panic In debug mode there will be a panic with the line number as an error code if
+ (iDrive value is not between EDriveA and EDriveZ)
+*/
+CDriveSpace::CDriveSpace(RFs& aFs, TDriveNumber aDrive) :
+ iFs(aFs),
+ iDrive(aDrive)
+ {
+ __ASSERT(iDrive >= EDriveA && iDrive <= EDriveZ);
+ }
+
+/**
+Frees the reserved disk space.
+@panic In debug mode there will be a panic with the line number as an error code if
+ (iGrantAccessRefCnt != 0)
+*/
+CDriveSpace::~CDriveSpace()
+ {
+ __ASSERT(iGrantAccessRefCnt == 0);
+ if(iGrantAccessRefCnt > 0)
+ {
+ (void)iFs.ReleaseReserveAccess(static_cast <TInt> (iDrive));
+ }
+ (void)iFs.ReserveDriveSpace(static_cast <TInt> (iDrive), 0);
+ }
+
+/**
+Standard phase-two construction method for creation of CDriveSpace objects.
+It will reserve a predefined amount of a disk space, enough for the most of the
+"delete" transactions, used by the applications.
+@leave RFs::ReserveDriveSpace() return values
+@see RFs::ReserveDriveSpace()
+*/
+void CDriveSpace::ConstructL()
+ {
+ __LEAVE_IF_ERROR(iFs.ReserveDriveSpace(static_cast <TInt> (iDrive), KReservedDiskSpace));
+ }
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+//RDriveSpaceCol class
+
+/**
+@param aFs File session instance
+*/
+RDriveSpaceCol::RDriveSpaceCol(RFs& aFs) :
+ iFs(aFs)
+ {
+ }
+
+/**
+The method releases all the resources used by RDriveSpaceCol object, including and
+reserved drive spaces on all drives in the collection.
+*/
+void RDriveSpaceCol::Close()
+ {
+ //Forced release of the reserved space
+ for(TInt i=iDriveSpaceCol.Count()-1;i>=0;--i)
+ {
+ delete iDriveSpaceCol[i];
+ }
+ iDriveSpaceCol.Close();
+ }
+
+/**
+The method returns a pointer to the CDriveSpace object, which handles all drive space
+requests, related to a particular drive.
+@param aDrive Drive number.
+@return A pointer to the CDriveSpace object, which handles drive space reservation requests
+ for aDriveNo drive. If there is no such object, the method returns NULL.
+*/
+CDriveSpace* RDriveSpaceCol::Find(TDriveNumber aDrive)
+ {
+ for(TInt index=iDriveSpaceCol.Count()-1;index>=0;--index)
+ {
+ if(iDriveSpaceCol[index]->iDrive == aDrive)
+ {
+ return iDriveSpaceCol[index];
+ }
+ }
+ return NULL;
+ }
+
+/**
+The method creates a new CDriveSpace object, adds it to the collection and
+returns a pointer to it.
+@param aDrive Drive number.
+@return A pointer to the created CDriveSpace object, which handles drive space
+ reservation requests for aDriveNo drive.
+@leave System-wide error codes, including KErrNoMemory.
+@panic In debug mode there will be a panic with the line number as an error code if
+ a CDriveSpace object already exists for aDrive.
+*/
+CDriveSpace* RDriveSpaceCol::CreateAddL(TDriveNumber aDrive)
+ {
+ __ASSERT(!Find(aDrive));
+ CDriveSpace* drvSpace = CDriveSpace::NewLC(iFs, aDrive);
+ __LEAVE_IF_ERROR(iDriveSpaceCol.Append(drvSpace));
+ CleanupStack::Pop(drvSpace);
+ return drvSpace;
+ }
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+//TDriveSpaceRq class
+
+/**
+@param aDriveSpace A reference to the CDriveSpace object, which handles the reservation requests
+ for a particular drive.
+*/
+CDbsSessDriveSpace::TDriveSpaceRq::TDriveSpaceRq(CDriveSpace& aDriveSpace) :
+ iDriveSpace(aDriveSpace),
+ iReserved(0),
+ iAccessGranted(0)
+ {
+ }
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+//CDbsSessDriveSpace class
+
+/**
+Standard phase-one factory method for creation of CDbsSessDriveSpace objects.
+@param aDriveSpaceCol A reference to the RDriveSpaceCol collection - there should be only one
+ per DBMS server.
+@return A pointer to the created CDbsSessDriveSpace object.
+@leave KErrNoMemory Out of memory
+*/
+CDbsSessDriveSpace* CDbsSessDriveSpace::NewL(RDriveSpaceCol& aDriveSpaceCol)
+ {
+ CDbsSessDriveSpace* self = new (ELeave) CDbsSessDriveSpace(aDriveSpaceCol);
+ return self;
+ }
+
+/**
+@param aDriveSpaceCol A reference to the RDriveSpaceCol collection - there should be only one
+ per DBMS server.
+*/
+CDbsSessDriveSpace::CDbsSessDriveSpace(RDriveSpaceCol& aDriveSpaceCol) :
+ iDriveSpaceCol(aDriveSpaceCol)
+ {
+ }
+
+/**
+Releases the allocated resources, which means the CDriveSpace::ReleaseAccess()
+will be called if TDriveSpaceRq::iAccessGranted for the related drive is set.
+*/
+CDbsSessDriveSpace::~CDbsSessDriveSpace()
+ {
+ for(TInt i=iDriveSpaceRqCol.Count()-1;i>=0;--i)
+ {
+ TDriveSpaceRq& rq = iDriveSpaceRqCol[i];
+ if(rq.iAccessGranted)
+ {
+ rq.iDriveSpace.ReleaseAccess();
+ }
+ //That's all!
+ //rq.iDriveSpace object shall not be destroyed or the reserved disk space - freed!
+ //It will be freed at the DBMS server shutdown.
+ }//end of: for(TInt i=iDriveSpaceRqCol.Count()-1;i>=0;--i)
+ iDriveSpaceRqCol.Close();
+ }
+
+/**
+The method reserves the requested amount of disk space.
+Because it is a shared file session between all DBMS sessions, a predefined amount of
+disk space per drive will be reserved at the moment of the first request made by some of
+the DBMS sessions. All the requests after the first (for a particular disk drive) will
+be completed successfully without actually reserving a disk space.
+Only the state of the related TDriveSpaceRq object will be updated to make it possible to
+control reservation/freeing requests.
+@param aDrive Drive number to reserve space on.
+@leave KErrNoMemory Out of memory
+@leave KErrInUse This DBMS session has already reserved a disk space.
+@leave RFs::ReserveDriveSpace() return values
+@see RFs::ReserveDriveSpace()
+*/
+void CDbsSessDriveSpace::ReserveL(TDriveNumber aDrive)
+ {
+ TDriveSpaceRq& rq = GetL(aDrive);
+ if(rq.iReserved || rq.iAccessGranted)
+ {
+ //This DBMS session already reserved a disk space (or even has an access to it).
+ //The DBMS session has to free it and then can re-reserve it again.
+ __LEAVE(KErrInUse);
+ }
+ rq.iReserved = 1; //CDriveSpace object reserves a predefined amount of disk space at
+ //at the moment of its creation, so just set rq.iReserved to non-zero,
+ //indicating that this session has reserved a disk space.
+ }
+
+/**
+The method frees the reserved by the DBMS session disk space.
+The actual implementation won't free the reserved disk space. This will happen at the moment of
+the destruction of the related CDriveSpace object for aDrive drive.
+The method just updates the state of the related TDriveSpaceRq object to make it possible to
+control reservation/freeing requests.
+@param aDrive Drive number, which reserved space has to be freed.
+@panic In debug mode there will be a panic with the line number as an error code if
+ there is no TDriveSpaceRq object for aDrive.
+@panic In debug mode there will be a panic with the line number as an error code if
+ the reserved disk space is granted but not released.
+@panic In debug mode there will be a panic with the line number as an error code if
+ there is no reserved disk space for aDrive.
+*/
+void CDbsSessDriveSpace::Free(TDriveNumber aDrive)
+ {
+ TDriveSpaceRq* rq = Find(aDrive);
+ __ASSERT(rq);//Probably an attempt to free non-reserved disk space.
+ __ASSERT(!rq->iAccessGranted);//An attempt to free reserved and granted disk space.
+ __ASSERT(rq->iReserved);//Probably an attempt to free non-reserved disk space.
+ if(rq)
+ {
+ rq->iReserved = 0;//Set it to 0, without actually freeing the reserved disk space.
+ //It is shared between all DBMS sessions.
+ }
+ }
+
+/**
+Gets an access to the reserved drive space.
+@param aDriveNo Drive number with a reserved disk space, an access to which is requested
+@leave KErrArgument There is no reserved disk space on aDrive.
+@leave KErrInUse An access to the reserved space has already been granted.
+@leave RFs::GetReserveAccess() return values
+@see RFs::GetReserveAccess()
+*/
+void CDbsSessDriveSpace::GrantAccessL(TDriveNumber aDrive)
+ {
+ TDriveSpaceRq* rq = Find(aDrive);
+ if(!rq)
+ {//Probably an attempt to get an access to a non-reserved disk space.
+ __LEAVE(KErrArgument);
+ }
+ if(!rq->iReserved)
+ {//Probably an attempt to get an access to a non-reserved disk space.
+ __LEAVE(KErrArgument);
+ }
+ if(rq->iAccessGranted)
+ {//Probably an attempt to get an access twice to the reserved disk space.
+ __LEAVE(KErrInUse);
+ }
+ rq->iDriveSpace.GrantAccessL();
+ rq->iAccessGranted = 1;
+ }
+
+/**
+Releases the access to the reserved drive space.
+@param aDriveNo Drive number with a reserved disk space, the access to which has to be released.
+@panic In debug mode there will be a panic with the line number as an error code if
+ there is no TDriveSpaceRq object for aDrive.
+@panic In debug mode there will be a panic with the line number as an error code if
+ there is no reserved disk space for aDrive.
+@panic In debug mode there will be a panic with the line number as an error code if
+ there is no granted access to the reserved disk space.
+*/
+void CDbsSessDriveSpace::ReleaseAccess(TDriveNumber aDrive)
+ {
+ TDriveSpaceRq* rq = Find(aDrive);
+ __ASSERT(rq);//Probably an attempt to release the access to a non-reserved disk space.
+ if(rq)
+ {
+ __ASSERT(rq->iReserved);//Probably an attempt to release the access to a non-reserved disk space.
+ __ASSERT(rq->iAccessGranted);//Probably an attempt to grant an access to the reserved disk spave twice.
+ if(rq->iReserved && rq->iAccessGranted)
+ {
+ rq->iDriveSpace.ReleaseAccess();
+ rq->iAccessGranted = 0;
+ }
+ }
+ }
+
+/**
+The method searches iDriveSpaceRqCol collection for TDriveSpaceRq object, which drive number
+is the same as aDrive parameter.
+@param aDrive Drive number
+@return A pointer to the TDriveSpaceRq object, which has the same drive number
+ NULL, if there is no such opject.
+*/
+CDbsSessDriveSpace::TDriveSpaceRq* CDbsSessDriveSpace::Find(TDriveNumber aDrive)
+ {
+ for(TInt index=iDriveSpaceRqCol.Count()-1;index>=0;--index)
+ {
+ if(iDriveSpaceRqCol[index].iDriveSpace.Drive() == aDrive)
+ {
+ return &iDriveSpaceRqCol[index];
+ }
+ }
+ return NULL;
+ }
+
+/**
+The method creates a new TDriveSpaceRq object with aDrive as a drive number and adds it
+to iDriveSpaceRqCol collection.
+@param aDrive Drive number
+@return A reference to the created TDriveSpaceRq object
+@leave System-wide error codes, including KErrNoMemory.
+@panic In debug mode there will be a panic with the line number as an error code if
+ there is an existing TDriveSpaceRq object for aDrive.
+*/
+CDbsSessDriveSpace::TDriveSpaceRq& CDbsSessDriveSpace::CreateAddL(TDriveNumber aDrive)
+ {
+ __ASSERT(!Find(aDrive));
+ //Check iDriveSpaceCol collection if there is a CDriveSpace object, which was already
+ //created for aDrive.
+ CDriveSpace* drvSpace = iDriveSpaceCol.Find(aDrive);
+ if(!drvSpace)
+ {//There is no CDriveSpace object for aDrive. It has to be created.
+ drvSpace = iDriveSpaceCol.CreateAddL(aDrive);
+ }
+ __ASSERT(drvSpace);
+ //Now we have the related CDriveSpace object for aDrive.
+ //Create new TDriveSpaceRq object and add it to iDriveSpaceRqCol collection.
+ __LEAVE_IF_ERROR(iDriveSpaceRqCol.Append(TDriveSpaceRq(*drvSpace)));
+ //If Append() call fails, then we have CDriveSpace object created but not deleted.
+ //It is not a problem, because CDriveSpace object was added to iDriveSpaceCol and will
+ //be destroyed when iDriveSpaceCol is destroyed.
+ return iDriveSpaceRqCol[iDriveSpaceRqCol.Count() - 1];
+ }
+
+/**
+This method combines the functionality of CDbsSessDriveSpace::Find() and
+CDbsSessDriveSpace::CreateAddL() methods.
+It will search for a TDriveSpaceRq object with the same drive number as aDrive.
+If such object doesn not exist, it will be created, added to iDriveSpaceRqCol and a reference
+to it - returned.
+@param aDrive Drive number
+@return A reference to the TDriveSpaceRq object, responsible for aDrive drive.
+@leave System-wide error codes, including KErrNoMemory.
+@see CDbsSessDriveSpace::Find()
+@see CDbsSessDriveSpace::CreateAddL()
+*/
+CDbsSessDriveSpace::TDriveSpaceRq& CDbsSessDriveSpace::GetL(TDriveNumber aDrive)
+ {
+ TDriveSpaceRq* rq = Find(aDrive);
+ return rq ? *rq : CreateAddL(aDrive);
+ }