diff -r 000000000000 -r 08ec8eefde2f persistentstorage/centralrepository/cenrepsrv/obsrvr_noc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/centralrepository/cenrepsrv/obsrvr_noc.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,912 @@ +// 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: +// + +#include "obsrvr_noc.h" +#include "panic.h" +#include "shrepos.h" +#include "srvrepos_noc.h" +#include "log.h" +#include "cachemgr.h" + +#define TRAP_UNIFIED(_unifiedLeave, _function) \ + { \ + TInt _returnValue = 0; \ + TRAP(_unifiedLeave, _returnValue = _function); \ + TInt& __rref = _unifiedLeave; \ + __rref = _unifiedLeave | _returnValue; \ + } + +CObservable::~CObservable() + { + iObservers.Close(); + // cleanup owned objects if there's any left + iOpenRepositories.ResetAndDestroy(); + iRepositoryInfo.ResetAndDestroy(); +#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS + TInt multiRofsUidCount=iMultiRofsUidList.Count(); + for (TInt i=0;iConstructL(); +#endif + return self; + } + +void CObservable::AddObserverL(TUid aUid, CServerRepository* aRepositoryPointer) + { + TRepositoryObserverInfo info; + + info.iRepositoryUid = aUid; + info.iRepositoryPointer = aRepositoryPointer; + + TLinearOrder observerSortOrder(CObservable::ObserverSortOrder); + TInt err = iObservers.InsertInOrder(info, observerSortOrder); + if ((err != KErrNone)&&(err != KErrAlreadyExists)) + { + User::Leave(err); + } + } + +void CObservable::RemoveObserver(TUid aUid, CServerRepository* aRepositoryPointer, TInt aInMemoryIndex) + { + TRepositoryObserverInfo info; + + info.iRepositoryUid = aUid; + info.iRepositoryPointer = aRepositoryPointer; + + TLinearOrder observerSortOrder(CObservable::ObserverSortOrder); + + TInt i = iObservers.FindInOrder(info, observerSortOrder); + if (i!=KErrNotFound) + { + // we remove the observer we find listening on the repository + iObservers.Remove(i); + if (iObservers.SpecificFindInSignedKeyOrder(info, EArrayFindMode_Any)!=KErrNotFound) + { + //if there are more + __CENTREP_TRACE1("CENTREP: Observer Removed when closing repository %x", aUid); + } + else + { + // removed the last observer with the given uid + // if the repository is in memory, try evicting it + if (aInMemoryIndex>=0) + { + // Check cache size and carry out forced eviction if necessary + // Start Eviction if the repository fits in the cache + if (TServerResources::iCacheManager->Enabled()&& + TServerResources::iCacheManager->StartEviction(GetOpenRepository(aInMemoryIndex))) + { + // Repository added to the idle list in eviction order + __CENTREP_TRACE2("CENTREP: Repository Became Idle when closing repository %x size %d", aUid, GetOpenRepository(aInMemoryIndex)->Size()); + } + else + { + __CENTREP_TRACE1("CENTREP: Repository Delete when closing repository %x", aUid); + // Remove and Delete Open Repository + delete iOpenRepositories[aInMemoryIndex]; + iOpenRepositories.Remove(aInMemoryIndex); + } + } + // if no clients are connected on this repository, we no longer need the transaction information + RemoveSharedRepositoryInfo(aUid); + } + } + } + +void CObservable::Notify(TUid aUid, TUint32 aVal) const + { + TInt i = FindConnectedRepository(aUid); + if (i != KErrNotFound) + { + for(;(iNotifier()->Notify(aVal); + } + } + } + +TInt CObservable::FindConnectedRepository(TUid aUid) const + { + TRepositoryObserverInfo info; + info.iRepositoryUid = aUid; + + return iObservers.SpecificFindInSignedKeyOrder(info, EArrayFindMode_First); + } + +#ifdef CACHE_OOM_TESTABILITY +void CObservable::Reset() + { + iObservers.Reset(); + iOpenRepositories.Reset(); + iRepositoryInfo.Reset(); + } + +void CObservable::CloseiOpenRepositories() + { + for(TInt i=iOpenRepositories.Count()-1; i>=0; i--) + { + delete iOpenRepositories[i]; + iOpenRepositories.Remove(i); + } + ASSERT(iOpenRepositories.Count()==0); + iOpenRepositories.Close(); + } + +void CObservable::CloseiRepositoryInfo() + { + for(TInt i=iRepositoryInfo.Count()-1; i>=0; i--) + { + delete iRepositoryInfo[i]; + iRepositoryInfo.Remove(i); + } + ASSERT(iRepositoryInfo.Count()==0); + iRepositoryInfo.Close(); + } + +#endif + +/** +This function compares two UID's and indicates their sorting order. This +implementation avoids overflow problems inherent in 'return aUid1-aUid2' +implementations. +*/ +TInt CObservable::CompareTUidValues(TInt aUid1, TInt aUid2) + { + if (aUid1 > aUid2) + return 1; + if (aUid1 < aUid2) + return -1; + return 0; + } + + +TInt CObservable::ObserverSortOrder(const TRepositoryObserverInfo &aRepository1, const TRepositoryObserverInfo &aRepository2) + { + TInt result; + + result = CompareTUidValues(aRepository1.iRepositoryUid.iUid, aRepository2.iRepositoryUid.iUid); + if (result == 0) + { + if (aRepository1.iRepositoryPointer > aRepository2.iRepositoryPointer) + return 1; + if (aRepository1.iRepositoryPointer < aRepository2.iRepositoryPointer) + return -1; + } + + return result; + } + +void CObservable::RemoveOpenRepository(CSharedRepository* aRepository) + { + TInt index = iOpenRepositories.Find(aRepository); + + if (index>=0) + { + // we don't fail any transactions here anymore, because transactions can now survive NOC repository + // unloads. The shared information about transactions is kept in memory seperately as long as a + // client is connected. + iOpenRepositories.Remove(index); + delete aRepository; + } + } + +TInt CObservable::FindOpenRepository(TUid aUid) const + { + TInt i; + TInt count=iOpenRepositories.Count(); + for(i=count-1; i>=0; i--) + { + if(iOpenRepositories[i]->Uid()==aUid) + { + break; + } + } + return i; + } + +TInt CObservable::ReadIniFileL(CSharedRepository*& aRepository, TCentRepLocation aLocation) + { + TInt r=KErrNone; + CIniFileIn* inifile = 0; + + HBufC* fileName(NULL); + //allocates memory on the heap + TServerResources::CreateRepositoryFileNameLC(fileName, aRepository->Uid(), aLocation, EIni); + r = CIniFileIn::NewLC(TServerResources::iFs,inifile,*fileName); + if(r==KErrNone) + { + r=ReadSettingsL(inifile, aRepository); + if(r==KErrCorrupt) + { + // File is corrupt, if it's not the ROM file, delete it + if(fileName && aLocation != ERom) + User::LeaveIfError(TServerResources::iFs.Delete(*fileName)); + // Delete any repository settings that may have been read in + aRepository->GetSettings().Reset(); + } + } + + CleanupStack::PopAndDestroy(inifile); // inifile + CleanupStack::PopAndDestroy(fileName); // filename + return r; + } + +#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS + +// Function to compare two TMultiRofsList's. +TInt CObservable::CompareUid(const TMultiRofsList& aUid1, const TMultiRofsList& aUid2) + { + if (aUid1.iRepUid.iUid < aUid2.iRepUid.iUid) + return -1 ; + if (aUid1.iRepUid.iUid > aUid2.iRepUid.iUid) + return 1 ; + return 0 ; + } + +void CObservable::ConstructL() + { + //now search for repositories uid that might be composed of multi rofs +#ifndef CENTREP_CONV_TOOL + if (TServerResources::iRomDirectory) + { + TFileName searchFileFormat; + searchFileFormat.Append(*(TServerResources::iRomDirectory)); + searchFileFormat.Append(_L("????????.???[*-00]")); + CDir* entryList=NULL; + User::LeaveIfError(TServerResources::iFs.GetDir(searchFileFormat,KEntryAttNormal,ESortByName,entryList)); + CleanupStack::PushL(entryList); + ProcessMultiRofsListL(*entryList); + CleanupStack::PopAndDestroy(entryList); + } +#endif + } + +void CObservable::ProcessMultiRofsListL(const CDir& aList) + { + TLex parser; + TUint32 uidNum; + TUint8 mountId; + TLinearOrder reposSortOrder(CompareUid); + TInt count=aList.Count(); + iMultiRofsUidList.ReserveL(count); + for (TInt i=0;i[id-00] + //Extract the Uid first + parser.Assign(aList[i].iName.Left(8)); + User::LeaveIfError(parser.Val(uidNum,EHex)); + + //Extract the Mount id now, see the file format above + parser.Assign(aList[i].iName.Mid(13,2)); + User::LeaveIfError(parser.Val(mountId,EHex)); + + //Now find whether this uid is already in the list + TMultiRofsList find(TUid::Uid(uidNum)); + //passing it the extension of the file + TRofsFlag newFlag(aList[i].iName.Mid(9,3),mountId); + + TInt err=iMultiRofsUidList.FindInOrder(find,reposSortOrder); + if (err==KErrNotFound) + { + //new entry + TMultiRofsList newEntry(TUid::Uid(uidNum)); + newEntry.iMountFlagList.AppendL(newFlag); + iMultiRofsUidList.InsertInOrderL(newEntry,reposSortOrder); + } + else + { + //entry exist, just need to update the array inside TMultiRofsList + err=iMultiRofsUidList[err].iMountFlagList.InsertInOrder(newFlag,TRofsFlag::CompareFlag); + //ignore KErrAlreadyExists which might be the case if a txt and cre found on the same + //rofs but the cre is preferred. + if (err!=KErrNone && err!=KErrAlreadyExists) + { + User::Leave(err); + } + } + } + } + + +void CObservable::OverrideSettingL(TServerSetting& aBaseSetting,const TServerSetting& aOvSetting,CSharedRepository* aCoreRepository,TBool aNewOv,TBool aNewOvIndivPolicy) + { + TUint32 ovId=aOvSetting.Key(); + + //---------------------CHECK AND SET THE META---------------------------- + TBool indivOvMeta=aOvSetting.IsIndividualMeta()!=0; + //if individually specified meta override this + if (indivOvMeta) + { + aBaseSetting.SetMeta(aOvSetting.Meta()); + } + //if not specified only when it is new we set it from the default meta + else + { + if (aNewOv) + aCoreRepository->SetMetaDataOnRead(aBaseSetting,EFalse); + } + + //----------------------CHECK AND SET THE PLATSEC---------------------------- + TLinearOrder order(&CHeapRepository::CompareKeyIds); + TSettingsAccessPolicy* ovTs=aOvSetting.AccessPolicy(); + TSettingsAccessPolicy* coreTs=aCoreRepository->GetFallbackAccessPolicy(ovId,ETrue); + //new setting defined + if (aNewOv) + { + //specify own settings + if (aNewOvIndivPolicy) + { + TSettingsAccessPolicy* newPol=new (ELeave)TSettingsAccessPolicy(*(const_cast + (aOvSetting.GetReadAccessPolicy())),*(const_cast(aOvSetting.GetWriteAccessPolicy())),ovId,ovTs->HighKey(),ovTs->KeyMask()); + CleanupStack::PushL(newPol); + //for single setting policy, the highkey is used to indicate whether the setting define its own read policy or it is just a fallback + if (ovTs->HighKey()==0) + { + newPol->iReadAccessPolicy=*(coreTs->GetReadAccessPolicy()); + } + //for single setting policy, the keymask is used to indicate whether the setting define its own write policy or it is just a fallback + if (ovTs->KeyMask()==0) + { + newPol->iWriteAccessPolicy=*(coreTs->GetWriteAccessPolicy()); + } + //insert the new one and set the setting policy to point to this + aCoreRepository->iSimRep->SinglePolicyArray().InsertInOrderL(newPol,order); + aBaseSetting.SetAccessPolicy(newPol); + CleanupStack::Pop(newPol); + } + //no individual setting policy specified so revert to the default policy in the base + else + { + aBaseSetting.SetAccessPolicy(coreTs); + } + } + //old setting + else + { + //if no individual policy specified do nothing as this keeps what we have in the base setting + if (aNewOvIndivPolicy) + { + TInt baseIndividualPol=aCoreRepository->iSimRep->SinglePolicyArray().Find(aBaseSetting.AccessPolicy()); + if (baseIndividualPol==KErrNotFound) + { + //no base individual but overriding specify one so create one and insert into list + //point the old base setting to this newly defined invididual setting + TSettingsAccessPolicy* newPol=new (ELeave)TSettingsAccessPolicy(*(const_cast + (aOvSetting.GetReadAccessPolicy())),*(const_cast(aOvSetting.GetWriteAccessPolicy())),ovId,ovTs->HighKey(),ovTs->KeyMask()); + CleanupStack::PushL(newPol); + //for single setting policy, the highkey is used to indicate whether the setting define its own read policy or it is just a fallback + if (ovTs->HighKey()==0) + { + newPol->iReadAccessPolicy=*(coreTs->GetReadAccessPolicy()); + } + //for single setting policy, the keymask is used to indicate whether the setting define its own write policy or it is just a fallback + if (ovTs->KeyMask()==0) + { + newPol->iWriteAccessPolicy=*(coreTs->GetWriteAccessPolicy()); + } + //insert the new one and set the setting policy to point to this + aCoreRepository->iSimRep->SinglePolicyArray().InsertInOrderL(newPol,order); + aBaseSetting.SetAccessPolicy(newPol); + CleanupStack::Pop(newPol); + } + else + { + TSettingsAccessPolicy* oldPol=aBaseSetting.AccessPolicy(); + //existing individual already exist, just update them + //for single setting policy, the highkey is used to indicate whether the setting define its own read policy or it is just a fallback + if (ovTs->HighKey()!=0) + { + oldPol->iReadAccessPolicy=*(aOvSetting.GetReadAccessPolicy()); + } + //for single setting policy, the keymask is used to indicate whether the setting define its own write policy or it is just a fallback + if (ovTs->KeyMask()!=0) + { + oldPol->iWriteAccessPolicy=*(aOvSetting.GetWriteAccessPolicy()); + } + } + } + } + + //---------------------SET THE VALUE--------------------------------------- + //override the value only if it is a new setting or an old setting with value modified + if (aNewOv || (!aNewOv && aBaseSetting!=aOvSetting)) + User::LeaveIfError(aBaseSetting.CopyTypeValue(aOvSetting)); + + //need to set it clean as this is still ROM settings + aBaseSetting.SetClean(); + } + +//Function containing the rule of merging repositories to a core repository +//such as -ignoring of the global properties(non-overriden) +// -type cannot be overriden +void CObservable::MergeRepositoryL(CSharedRepository* aCoreRepository,CHeapRepository* aOverrideRepository) + { + /** + We may want to verify that the following global properties match + -OwnerUid + -Uid + We may want to give warning if they try to have global propertie section in the overriding layers + although this obviously now can be ignored now, just need to make sure that repository follows the format + and not corrupted + */ + TSettingsAccessPolicy defaultTs=aOverrideRepository->GetDefaultAccessPolicy(); + //lets panic first on debug mode only + //here we panic immediately if there is any defined in the range meta/policy(we can check individually if + //they do override later on,we will assume any definiton of global policy is invalid here + if ( aOverrideRepository->Owner() != aCoreRepository->iSimRep->Owner() + || (aOverrideRepository->DefaultMeta()!=0 && aOverrideRepository->DefaultMeta()!= aCoreRepository->iSimRep->DefaultMeta()) + || (defaultTs.HighKey()!=0 && aOverrideRepository->GetDefaultReadAccessPolicy().Package() != aCoreRepository->iSimRep->GetDefaultReadAccessPolicy().Package()) + || (defaultTs.KeyMask()!=0 && aOverrideRepository->GetDefaultWriteAccessPolicy().Package()!= aCoreRepository->iSimRep->GetDefaultWriteAccessPolicy().Package()) + || (aOverrideRepository->RangeMetaArray().Count()!=0 && !(aCoreRepository->iSimRep->RangeMetaArray().IsEqual(aOverrideRepository->RangeMetaArray()))) + || (aOverrideRepository->RangePolicyArray().Count()!=0 && !(aCoreRepository->iSimRep->RangePolicyArray().IsEqual(aOverrideRepository->RangePolicyArray()) + ))) + { + #ifdef _DEBUG + RDebug::Printf("Illegal Global Properties Overriding"); + #endif + User::Leave(KErrMultiRofsGlobalOverride); + } + + TInt single_count=aOverrideRepository->SettingsArray().Count(); + for (TInt i=0;iSettingsArray()[i]; + TUint32 ovId=ovTs.Key(); + + //find whether it exist in the core + TServerSetting* coreTs=aCoreRepository->GetSettings().Find(ovId); + //check whether in the overriding repository,the policy is individually specified policy + TInt ovIndividualPol=aOverrideRepository->SinglePolicyArray().Find(ovTs.AccessPolicy()); + if (coreTs) + { + //found in core, need to check the type is the same else Panic + if (coreTs->Type()!=ovTs.Type()) + { + #ifdef _DEBUG + RDebug::Printf("Illegal Setting Type Overriding"); + #endif + User::Leave(KErrMultiRofsTypeOverride); + } + OverrideSettingL(*coreTs,ovTs,aCoreRepository,EFalse,ovIndividualPol!=KErrNotFound); + } + else + { + //this is a newly defined setting + TServerSetting newTs(ovTs.Key()); + OverrideSettingL(newTs,ovTs,aCoreRepository,ETrue,ovIndividualPol!=KErrNotFound); + //finally insert into the RSettingsArray for this new setting + aCoreRepository->iSimRep->SettingsArray().OrderedInsertL(newTs); + } + } + + } + +//Function on initialising a repository of multi ROFS files +void CObservable::MergeMultiRofsL(TBool aCoreInitialized,CSharedRepository* aCoreRepository,const RArray& aOverridingFileList) + { + //load all the files and construct an array of CHeapRepository to merge content into it + TInt sortedCount=aOverridingFileList.Count(); + TFileName repFileName; + for (TInt i=0;iUid().iUid,&extPointer,rofsFlag.iFlag & 0xFF); + //only when the core is not initialized, the first item in the list now becomes the core + if (!aCoreInitialized && i==0) + { + if (isTxt) + { + CIniFileIn* iniFile; + TInt err=CIniFileIn::NewLC(TServerResources::iFs,iniFile,repFileName); + User::LeaveIfError(err); + aCoreRepository->ReloadContentL(*iniFile,ETrue); + CleanupStack::PopAndDestroy(iniFile);//iniFile + } + else + { + aCoreRepository->iSimRep->CreateRepositoryFromCreFileL(TServerResources::iFs,repFileName); + } + } + else + { + CHeapRepository* repos=CHeapRepository::NewL(aCoreRepository->Uid()); + CleanupStack::PushL(repos); + + if (isTxt) + { + CIniFileIn* iniFile; + TInt err=CIniFileIn::NewLC(TServerResources::iFs,iniFile,repFileName); + User::LeaveIfError(err); + repos->ReloadContentL(*iniFile); + CleanupStack::PopAndDestroy(iniFile);//iniFile + } + else + { + TUint8 creVersion; + repos->CreateRepositoryFromCreFileL(TServerResources::iFs,repFileName,creVersion); + //need to check the CRE version in the overloading layer + if (creVersionSettingsArray().SetIsDefault(ETrue); + MergeRepositoryL(aCoreRepository,repos); + + CleanupStack::PopAndDestroy(repos); //repos + } + } + } +#endif + +TInt CObservable::CreateRepositoryL(CSharedRepository* aRepository, TCentRepLocation aLocation) + { + aRepository->GetSettings().SetIsDefault(aLocation!=EPersists); + TInt err(KErrNotFound); + + err = aRepository->CreateRepositoryFromCreFileL(aLocation); + if(err==KErrNotFound) + { + if (aLocation!=EPersists) + err = ReadIniFileL(aRepository,aLocation); + } + //for ROM might want to consider the possibility of multi rofs file +#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS + if (aLocation==ERom && iMultiRofsUidList.Count()!=0) + { + //if there is error and not because of non-existant we should return error immediately + //and if it is fine but the uid does not match one of the multirofsuidlsit this means that + //repository is not composed of multi file. + if (err==KErrNone || err==KErrNotFound) + { + TMultiRofsList find(aRepository->Uid()); + TLinearOrder sort_order(CompareUid); + TInt index=iMultiRofsUidList.FindInOrder(find,sort_order); + if (index==KErrNotFound) + return err; + //if the first layer has already got the exattrib=U we should leave with KErrMultiRofsIllegalRofs + if (err==KErrNotFound && index!=KErrNotFound) + User::Leave(KErrMultiRofsIllegalRofs); + //the list exist in one of the mappings stored earlier, get the name and construct them + TRAP(err,MergeMultiRofsL(err==KErrNone,aRepository,iMultiRofsUidList[index].iMountFlagList)); + if (err==KErrNoMemory) + User::LeaveNoMemory(); + } + } +#endif + return( err); + } + +/** +In order to create a repository this routine looks for a .cre or .txt file. +Txt and cre files can co-exist in install and ROM but not in persists location. +If a persists txt file exists, the first write to the repository will cause a +cre file to be created and the txt file to be deleted. +If both files exist in the same location, the .cre is picked up first. +If the .cre file is not found,a .txt file from the same location is tried. +Otherwise if the .cre file is corrupted,it tries a .cre file from a next location. + +Note: +If a cre file exists at a particular location, even if the cre file is corrupt a txt +file will not be searched for in the same location. +*/ + +TInt CObservable::CreateRepositoryL(CSharedRepository*& aRepository, CIniFileIn::TIniFileOpenMode aIniFileOpenMode) + { + TInt err(KErrNotFound); + + switch (aIniFileOpenMode) + { + case CIniFileIn::EAuto: + { + // Look in persists dir + err=CreateRepositoryL(aRepository, EPersists); + + if(err==KErrNone) + { + return err; + } + + // No persists file - look in ROM dir + // Do this before looking in the install dir, because if there is + // a ROM file, an install file and no persists file then this + // repository is being opened after a SW install but before the + // merge. In this case the install file shouldn't be opened + // until after the merge. + err=CreateRepositoryL(aRepository, ERom); + + if(err==KErrNone) + { + break; + } + else if(err==KErrNotFound) + { + // Look in install directory only if there was no ROM or persists file + err=CreateRepositoryL(aRepository, EInstall); + if(err==KErrNone) + { + TTime installFileTimeStamp=TServerResources::CentrepFileTimeStampL(aRepository->Uid(), EInstall); + aRepository->SetInstallTime(installFileTimeStamp); + } + } + break; + } + + case CIniFileIn::EInstallOnly: + { + err=CreateRepositoryL(aRepository, EInstall); + break; + } + + case CIniFileIn::ERomOnly: + { + err=CreateRepositoryL(aRepository, ERom); + break; + } + } + + return err; + } + +TInt CObservable::ReadSettingsL(CIniFileIn *aIniFile, CSharedRepository* aRep) + { + return aRep->ReloadContentL(*aIniFile, ETrue); + } + +void CObservable::LoadRepositoryLC(TUid aUid, TBool aFailIfNotFound, CSharedRepository*& aRepository, CIniFileIn::TIniFileOpenMode aIniFileOpenMode) + { + // Calculate the amount of memory this repository will take in the heap + // by checking the heap size before and after the internalization + RHeap& myHeap = User::Heap(); + TInt firstSize = myHeap.Size(); + TInt biggestBlock; + TInt firstAvail = myHeap.Available(biggestBlock); + + aRepository = CSharedRepository::NewL(aUid); +#ifdef CACHE_OOM_TESTABILITY + if ((aRepository==NULL)&&!iTrapOOMOnOpen) + { + User::Leave(KErrNoMemory); + } +#endif + if ((aRepository==NULL)&&TServerResources::iCacheManager->Enabled()) + { + // If cache enabled, try recovery by releasing the cache + TServerResources::iCacheManager->FlushCache(EFalse); + // retry + aRepository = CSharedRepository::NewL(aUid); + } + // If still no memory, return error + if (aRepository==NULL) + { + User::Leave(KErrNoMemory); + } + else // successfully created the object, so push it into the cleanup stack + { + CleanupStack::PushL(aRepository); + } + + // Now that we have enough memory for the object and constructed it properly + // we try to load it. We trap all errors, either from leaving functions or error code + // returning functions and unify them (in all cases only one of these codes will + // contain a valid value and the other will be 0, and for our purposes we treat + // all errors the same no matter if they're thrown or returned) + + TInt unifiedErrorCode; + TRAP_UNIFIED(unifiedErrorCode, CreateRepositoryL(aRepository, aIniFileOpenMode)); + + if (unifiedErrorCode!=KErrNone) + { + switch(unifiedErrorCode) + { + case KErrNoMemory: + { + if (TServerResources::iCacheManager->Enabled()) // cache enabled + { +#ifdef CACHE_OOM_TESTABILITY + if (!iTrapOOMOnOpen) + { + User::Leave(KErrNoMemory); + } +#endif + // Flush cache + TServerResources::iCacheManager->FlushCache(ETrue); + + firstSize = myHeap.Size(); + firstAvail = myHeap.Available(biggestBlock); + + //retry + TRAP_UNIFIED(unifiedErrorCode, CreateRepositoryL(aRepository, aIniFileOpenMode)); + } + } + break; + case KErrNotFound: + case KErrPathNotFound: + { + if (!aFailIfNotFound) // backup open + { + // override error condition and continue normally + unifiedErrorCode = KErrNone; + } + } + break; + } + } + // If unhandled, leave + User::LeaveIfError(unifiedErrorCode); + + // Otherwise, finalize calulations + TInt lastSize = myHeap.Size(); + TInt lastAvail = myHeap.Available(biggestBlock); + + TInt calcSize = (lastSize - lastAvail) - (firstSize - firstAvail); + // record repository size for cache algorithm purposes + aRepository->SetSize(calcSize); + } + +CSharedRepository* CObservable::AccessL(TUid aUid, TBool aFailIfNotFound) + { + CSharedRepository* rep = NULL; + + TInt i = FindOpenRepository(aUid); + if(i!=KErrNotFound) + { + rep = GetOpenRepository(i); + // repository still open, can safely call RestoreConsistencyL + rep->RestoreConsistencyL(); + } + else + { + // For memory usage testing purposes + RECORD_HEAP_SIZE(EMemLcnRepositoryOpen, aUid.iUid); + // Various error conditions are handled in this function + LoadRepositoryLC(aUid, aFailIfNotFound, rep, CIniFileIn::EAuto); + __CENTREP_TRACE1("CENTREP: Repository Load when opening repository %x", aUid.iUid); + // For memory usage testing purposes + RECORD_HEAP_SIZE(EMemLcnRepositoryOpen, aUid.iUid); + + AddOpenRepositoryL(rep); + + // We pop the rep here because if later call of TServerResources::AddOwnerIdLookupMapping fails of OOM + // the call of RemoveOpenRepository() will delete the repository before leave. + CleanupStack::Pop(rep); + + // Add owner mapping to list - Will fail if an entry already exists + // with this Repository UID but this doesn't matter + TUid owner = rep->Owner() ; + TInt err = TServerResources::AddOwnerIdLookupMapping(aUid.iUid, owner.iUid); + if (err == KErrNoMemory) + { + RemoveOpenRepository(rep); + User::Leave(err); + } + + //Find the location of the current transaction for this repository + const TInt offset (FindRepositoryInfo(aUid)); + if (offset >=0) //If there are no outstanding transactions + { + RefreshTransactorAccessPolicies(rep,offset); + } + } + + // re-start the timer + if (TServerResources::iCacheManager->Enabled()) + { + TServerResources::iCacheManager->StartEviction(rep); + } + + return rep; + } + +TInt CObservable::FindRepositoryInfo(TUid aUid) + { + TSharedRepositoryInfo info(aUid); + TLinearOrder infoSortOrder(CObservable::InfoSortOrder); + + return iRepositoryInfo.FindInOrder(&info, infoSortOrder); + } + +CObservable::TSharedRepositoryInfo* CObservable::SharedRepositoryInfo(TUid aUid) + { + TInt pos = FindRepositoryInfo(aUid); + return (pos!=KErrNotFound) ? iRepositoryInfo[pos] : NULL; + } + +CObservable::TSharedRepositoryInfo::TSharedRepositoryInfo(TUid aUid) : + iRepositoryUid(aUid), iTransactors(_FOFF(CRepositoryTransactor, iLink)), + iPessimisticTransactionLockCount(0), iNumActiveConcurrentReadWriteTransactions(0) + { + } + +TInt CObservable::InfoSortOrder(const TSharedRepositoryInfo &aRepository1, const TSharedRepositoryInfo &aRepository2) + { + return CompareTUidValues(aRepository1.iRepositoryUid.iUid, aRepository2.iRepositoryUid.iUid); + } + +void CObservable::AddSharedRepositoryInfoL(TUid aUid) + { + TSharedRepositoryInfo* shinfo = new(ELeave) TSharedRepositoryInfo(aUid); + + TLinearOrder infoSortOrder(CObservable::InfoSortOrder); + // Inserts if not already in the array, otherwise returns KErrAlreadyExists, which we handle gracefully + TInt err = iRepositoryInfo.InsertInOrder(shinfo, infoSortOrder); + if (err==KErrAlreadyExists) + { + delete shinfo; + } + else + { + if (err!=KErrNone) + delete shinfo; + User::LeaveIfError(err); + } + } + +void CObservable::RemoveSharedRepositoryInfo(TUid aUid) + { + TInt pos = FindRepositoryInfo(aUid); + if (pos!=KErrNotFound) + { + delete iRepositoryInfo[pos]; + iRepositoryInfo.Remove(pos); + } + } + + +void CObservable::RefreshTransactorAccessPolicies(CSharedRepository* aRepository,const TInt offset) + { + TSglQueIter iter(iRepositoryInfo[offset]->iTransactors); + CRepositoryTransactor* t (iter); + + while (iter++ != NULL) + { + const TInt count = t->iTransactionSettings.Count(); + for (TInt i=0; iiTransactionSettings[i]; + t->iTransactionSettings[i].SetAccessPolicy(aRepository->GetFallbackAccessPolicy(temp.Key())); + //Correct the access policy pointer so that its pointing to the new valid location + } + t = iter; + } + }