diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/sdbms/Sd_DriveSpace.cpp --- /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 (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 (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 (iDrive)); + } + (void)iFs.ReserveDriveSpace(static_cast (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 (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); + }