mtpfws/mtpfw/src/cmtphandleallocator.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:11:40 +0200
changeset 0 d0791faffa3f
permissions -rw-r--r--
Revision: 201003 Kit: 201005

// 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:
//


#include <mtp/mtpprotocolconstants.h>
#include "cmtphandleallocator.h"
#include "tmtptypeobjecthandle.h"
#include "dbutility.h"
#include "cmtpobjectstore.h"
    
static const TUint KMTPMinimumId = 0x00000000;
static const TUint KMTPMaximumId = 0x00FFFFFE;
static const TInt64 KMTPPOUIDStart = -1;
static const TInt  KMTPMaxDataProviderGranularity = 8;
#if defined(_DEBUG)
static const TInt  KMTPMaxDataProviderId = 0x00000100;
#endif


/**
Two-phase object construction
*/
CMTPHandleAllocator* CMTPHandleAllocator::NewL( CMTPObjectStore& aObjectStore )
	{
	CMTPHandleAllocator* self = new (ELeave) CMTPHandleAllocator(aObjectStore);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}
	
/**
destructor
*/	
CMTPHandleAllocator::~CMTPHandleAllocator()
	{
	iNextIds.Close();
	
    iNextIDPool.ResetAndDestroy();
	}

/**
Get the next object identifier (Handle) for the specified data provider.
@param aDataProviderId	The Id of the data provider 
@return the next object identifier (Handle)
@leave KErrOverFlow	if the object identifier has been exhausted for the data provider
*/	
TUint32 CMTPHandleAllocator::NextIdL(TUint aDataProviderId)
	{
	__ASSERT_DEBUG(aDataProviderId < KMTPMaxDataProviderId, User::Invariant());
	if (aDataProviderId >= iNextIds.Count())
	    {
	    ExtendArrayL(aDataProviderId);
	    }
	
	TUint result = ++iNextIds[aDataProviderId];
	if(result > KMTPMaximumId)
		{
		--iNextIds[aDataProviderId];
        result = NextIDFromPoolL(aDataProviderId);
		}
	
	TMTPTypeObjectHandle handle(result,  aDataProviderId);
	return handle.Value(); 
	}

TInt64 CMTPHandleAllocator::NextPOUIDL()
{
	return ++iNextPOUID;
}
/**
Initialize the allocator for this DP.  This must be called if and only if the
DP uses persistent objects, and some persistent objects exist in the object
store, so that later allocations do not duplicate earlier object IDs.
If it is called, it must therefore be called before any new objects are
allocated for this DP.
@param aDataProviderId	Id of the data provider 
@param aObjectId Object Id of the largest object already allocated,
or KMTPHandleNone if no objects have been allocated
*/

void CMTPHandleAllocator::SetIdL( TUint32 aHandleID, TInt64 aPOUID )
	{
	TUint dpID = TMTPTypeObjectHandle::DataProviderID(aHandleID);
	TUint objID = TMTPTypeObjectHandle::ObjectID(aHandleID);

	__ASSERT_DEBUG(dpID < KMTPMaxDataProviderId, User::Invariant());
	
	if ( dpID >= iNextIds.Count())
	    {
	    ExtendArrayL(dpID);
	    }
	
	if( objID > iNextIds[dpID] )
	    {
	    iNextIds[dpID] = objID ;
	    }
	if( aPOUID > iNextPOUID )
	    {
	    iNextPOUID = aPOUID;
	    }
	}

/**
Standard C++ constructor
*/	
CMTPHandleAllocator::CMTPHandleAllocator( CMTPObjectStore& aObjectStore):
	iObjectStore(aObjectStore),
	iNextIds(KMTPMaxDataProviderGranularity),
	iNextPOUID(KMTPPOUIDStart)
	{
	}

/**
Extends the array to handle more data providers. DP IDs are allocated
sequentially, so this way the array never needs to be much larger
than necessary.  This must only be called if the array size needs to be increased.
@param aDataProviderId the array must be sized to fit this data provider ID
*/	
void CMTPHandleAllocator::ExtendArrayL(TUint aDataProviderId)
	{
	__ASSERT_DEBUG(aDataProviderId >= iNextIds.Count(), User::Invariant());
	TInt increase = aDataProviderId - iNextIds.Count() + KMTPMaxDataProviderGranularity;
	while (increase--)
		{
		User::LeaveIfError(iNextIds.Append(KMTPMinimumId));
		}
	}
	
/**
Second-phase construction
*/	
void CMTPHandleAllocator::ConstructL()
	{
	ExtendArrayL(0);
	}

TBool CMTPHandleAllocator::AppendHandleBlockL( TUint aDataProviderId, TUint aNextID, TInt aSpace )
    {
    TInt index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending );
    if( index == KErrNotFound )
        {
        CDPHandleCache* cache = CDPHandleCache::NewLC(aDataProviderId);
        iNextIDPool.InsertInOrderL(cache , TLinearOrder<CDPHandleCache>(CDPHandleCache::HanldeCacheOrderFromAscending));
        CleanupStack::Pop(cache);
        
        index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending );
        }
    
    iNextIDPool[index]->AppendL( CDPHandleCache::THandleBlock( TMTPTypeObjectHandle::ObjectID(aNextID), aSpace) );
    
    
    if(iNextIDPool[index]->BlocksCount() < CDPHandleCache::MaxNumOfBlocks() )
        {
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }

TUint32 CMTPHandleAllocator::NextIDFromPoolL( TUint aDataProviderId )
    {
    TInt index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending );
    if( index == KErrNotFound )
        {
        iObjectStore.CalcFreeHandlesL(aDataProviderId);
        
        index = iNextIDPool.FindInOrder( aDataProviderId, CDPHandleCache::HanldeCacheOrderFromKeyAscending );
        if( index == KErrNotFound )
            {
            User::Leave(KErrOverflow);
            }
        }
    
    TUint32 ret = iNextIDPool[index]->NextHandleID();
    if( !iNextIDPool[index]->HasCache() )
        {
        iNextIDPool.Remove(index);
        }
    
    if(ret > KMTPMaximumId )
        {
        User::Leave(KErrOverflow);
        }
    
    return ret;
    }

CMTPHandleAllocator::CDPHandleCache::THandleBlock::THandleBlock(TUint aNextID, TInt aSpace):
    iNextID(aNextID),
    iSpace(aSpace)
    {
    }

TInt CMTPHandleAllocator::CDPHandleCache::HanldeCacheOrderFromAscending( const CDPHandleCache& aL, const CDPHandleCache& aR)
    {
    return aL.DPID() - aR.DPID();
    }

TInt CMTPHandleAllocator::CDPHandleCache::HanldeCacheOrderFromKeyAscending( const TUint* aL, const CDPHandleCache& aR)
    {
    return (*aL) - aR.DPID();
    }

CMTPHandleAllocator::CDPHandleCache::CDPHandleCache(TUint aDataProviderId ):
    iDPID(aDataProviderId)
    {
    }

CMTPHandleAllocator::CDPHandleCache::~CDPHandleCache()
    {
    iBlocks.Close();
    }

void CMTPHandleAllocator::CDPHandleCache::ConstructL()
    {
    }

CMTPHandleAllocator::CDPHandleCache* CMTPHandleAllocator::CDPHandleCache::NewLC( TUint aDataProviderId )
    {
    CDPHandleCache* self = new (ELeave) CDPHandleCache(aDataProviderId);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

TUint32 CMTPHandleAllocator::CDPHandleCache::NextHandleID()
    {
    TUint32 ret = KMTPMaximumId + 1;
    if(iBlocks.Count() == 0)
        {
        return ret;
        }
    
    ret = iBlocks[0].iNextID;
    --iBlocks[0].iSpace;
    
    if( 0 == iBlocks[0].iSpace )
        {
        iBlocks.Remove(0);
        }
    else
        {
        iBlocks[0].iNextID++;
        }
    
    return ret;
    }

void CMTPHandleAllocator::CDPHandleCache::AppendL( const THandleBlock& aBlock )
    {
    iBlocks.AppendL( aBlock );
    }