sl@0: // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "LogServViewChangeManager.h" sl@0: #include sl@0: #include "logservpanic.h" sl@0: #include "LogServDatabaseChangeInterface.h" sl@0: sl@0: // Constants sl@0: const TInt KLogServViewChangeDefinitionGranularity = 10; sl@0: const TInt KLogServViewChangeQueueGranularity = 3; sl@0: const TInt KLogServViewChangeBufferGranularity = 40; sl@0: sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: // -----> CLogServViewChangeManager (source) sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: CLogServViewChangeManager::CLogServViewChangeManager(MLogServDatabaseChangeInterface& aChangeInterface) sl@0: : iChangeInterface(aChangeInterface), iPendingChanges(KLogServViewChangeQueueGranularity) sl@0: { sl@0: } sl@0: sl@0: CLogServViewChangeManager::~CLogServViewChangeManager() sl@0: { sl@0: delete iTransientChangeDefinition; sl@0: // sl@0: iPendingChanges.ResetAndDestroy(); sl@0: iPendingChanges.Close(); sl@0: } sl@0: sl@0: void CLogServViewChangeManager::ConstructL() sl@0: { sl@0: iTransientChangeDefinition = CLogChangeDefinition::NewL(KLogServViewChangeDefinitionGranularity); sl@0: } sl@0: sl@0: CLogServViewChangeManager* CLogServViewChangeManager::NewL(MLogServDatabaseChangeInterface& aChangeInterface) sl@0: { sl@0: CLogServViewChangeManager* self = new(ELeave) CLogServViewChangeManager(aChangeInterface); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: void CLogServViewChangeManager::ChangeTransactionPrepare() sl@0: { sl@0: iTransientChangeDefinition->Reset(); sl@0: } sl@0: sl@0: void CLogServViewChangeManager::ChangeTransactionSubmitL(TLogId aId, TLogDatabaseChangeType aType, TInt aViewIndex) sl@0: { sl@0: iTransientChangeDefinition->AddL(aId, aType, aViewIndex); sl@0: } sl@0: sl@0: void CLogServViewChangeManager::ChangeTransactionCommitL() sl@0: { sl@0: // We can only tell the client-side view change observer about the changes if: sl@0: // sl@0: // (2) we actually have something to tell the client views (some changes) sl@0: // (3) we have an outstanding client-side change message pointer sl@0: // sl@0: const TInt count = iTransientChangeDefinition->Count(); sl@0: if (count > 0) // (2) sl@0: { sl@0: // Do we have any existing pending changes? We can't alter the contents of the sl@0: // first pending change, since the client may already be preparing a client-side sl@0: // buffer of the requisite size. We can, however, combine the 2nd batch of changes sl@0: // with this new set so there is less IPC required (although more memory). sl@0: const TInt pendingChangeCount = iPendingChanges.Count(); sl@0: if (pendingChangeCount >= 2) sl@0: { sl@0: CLogChangeDefinition* changeDef = CLogChangeDefinition::NewL(); sl@0: CleanupStack::PushL(changeDef); sl@0: // sl@0: CBufBase* buffer = iPendingChanges[1]; sl@0: RBufReadStream readStream(*buffer); sl@0: // sl@0: readStream >> *changeDef; sl@0: sl@0: // Add new changes sl@0: TLogId logId = KLogNullId; sl@0: TLogDatabaseChangeType type = ELogChangeTypeUndefined; sl@0: TInt viewIndex = 0; sl@0: // sl@0: for(TInt i=0; iAt(i, logId, viewIndex); sl@0: changeDef->AddL(logId, type, viewIndex); sl@0: } sl@0: sl@0: // Write the whole lot out again sl@0: buffer->Delete(0, buffer->Size()); sl@0: sl@0: RBufWriteStream writeStream(*buffer); sl@0: writeStream << *changeDef; sl@0: buffer->Compress(); sl@0: CleanupStack::PopAndDestroy(changeDef); sl@0: } sl@0: else sl@0: { sl@0: CBufBase* buffer = CBufFlat::NewL(KLogServViewChangeBufferGranularity); sl@0: CleanupStack::PushL(buffer); sl@0: sl@0: // Externalize changes sl@0: RBufWriteStream stream(*buffer); sl@0: stream << *iTransientChangeDefinition; sl@0: buffer->Compress(); sl@0: sl@0: // Add to container sl@0: User::LeaveIfError(iPendingChanges.Append(buffer)); sl@0: CleanupStack::Pop(buffer); sl@0: } sl@0: sl@0: // Notify if necessary - handles (3) implicitly sl@0: NotifyClient(); sl@0: } sl@0: sl@0: // Free some memory sl@0: iTransientChangeDefinition->Reset(); sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: void CLogServViewChangeManager::DeliverChangesL(const RMessage2& aMessage) sl@0: { sl@0: if (iPendingChanges.Count()) sl@0: { sl@0: CBufBase* headItem = iPendingChanges[0]; sl@0: // sl@0: const TInt expectedChangesSize = aMessage.Int1(); sl@0: const TPtr8 pBufferContents(headItem->Ptr(0)); sl@0: sl@0: // Check buffer size is as we expect sl@0: if (expectedChangesSize != pBufferContents.Size()) sl@0: ::PanicClientL(aMessage, ELogViewBadClientSideChangeBufferSize); sl@0: else sl@0: { sl@0: // Write back to client-side sl@0: aMessage.WriteL(2, pBufferContents); sl@0: sl@0: // Remove the item sl@0: iPendingChanges.Remove(0); sl@0: delete headItem; sl@0: } sl@0: } sl@0: else sl@0: ::PanicClientL(aMessage, ELogViewNoPendingChangesToDeliver); sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: void CLogServViewChangeManager::RequestChangeNotifications(const RMessage2& aMessage) sl@0: { sl@0: if (iClientSideChangeMessage == RMessagePtr2()) sl@0: { sl@0: // Notify if we have any cached changes... sl@0: iClientSideChangeMessage = aMessage; sl@0: NotifyClient(); sl@0: } sl@0: else sl@0: PanicClient(aMessage, ELogViewChangeRequestAlreadyIssued); sl@0: } sl@0: sl@0: void CLogServViewChangeManager::RequestChangeNotificationsCancel() sl@0: { sl@0: if (iClientSideChangeMessage != RMessagePtr2()) sl@0: CompleteClientChangeMessage(KErrCancel); sl@0: sl@0: // Zap all the pending changes too sl@0: iPendingChanges.ResetAndDestroy(); sl@0: iPendingChanges.GranularCompress(); sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: void CLogServViewChangeManager::NotifyClient() sl@0: { sl@0: const TInt count = iPendingChanges.Count(); sl@0: if (iClientSideChangeMessage != RMessagePtr2() && count) sl@0: { sl@0: CBufBase* headItem = iPendingChanges[0]; sl@0: const TInt messageSize = headItem->Size(); sl@0: CompleteClientChangeMessage(messageSize); sl@0: } sl@0: } sl@0: sl@0: void CLogServViewChangeManager::CompleteClientChangeMessage(TInt aCompletionCode) sl@0: { sl@0: __ASSERT_ALWAYS(iClientSideChangeMessage != RMessagePtr2(), Panic(ELogViewNoClientChangeMessageOutstanding)); sl@0: iClientSideChangeMessage.Complete(aCompletionCode); sl@0: }