loggingservices/eventlogger/LogServ/src/LogServViewChangeManager.cpp
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loggingservices/eventlogger/LogServ/src/LogServViewChangeManager.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,214 @@
+// Copyright (c) 2002-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 "LogServViewChangeManager.h"
+#include <s32mem.h>
+#include "logservpanic.h"
+#include "LogServDatabaseChangeInterface.h"
+
+// Constants
+const TInt KLogServViewChangeDefinitionGranularity = 10;
+const TInt KLogServViewChangeQueueGranularity = 3;
+const TInt KLogServViewChangeBufferGranularity = 40;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// -----> CLogServViewChangeManager (source)
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CLogServViewChangeManager::CLogServViewChangeManager(MLogServDatabaseChangeInterface& aChangeInterface)
+:	iChangeInterface(aChangeInterface), iPendingChanges(KLogServViewChangeQueueGranularity)
+	{
+	}
+
+CLogServViewChangeManager::~CLogServViewChangeManager()
+	{
+	delete iTransientChangeDefinition;
+	//
+	iPendingChanges.ResetAndDestroy();
+	iPendingChanges.Close();
+	}
+
+void CLogServViewChangeManager::ConstructL()
+	{
+	iTransientChangeDefinition = CLogChangeDefinition::NewL(KLogServViewChangeDefinitionGranularity);
+	}
+
+CLogServViewChangeManager* CLogServViewChangeManager::NewL(MLogServDatabaseChangeInterface& aChangeInterface)
+	{
+	CLogServViewChangeManager* self = new(ELeave) CLogServViewChangeManager(aChangeInterface);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServViewChangeManager::ChangeTransactionPrepare()
+	{
+	iTransientChangeDefinition->Reset();
+	}
+
+void CLogServViewChangeManager::ChangeTransactionSubmitL(TLogId aId, TLogDatabaseChangeType aType, TInt aViewIndex)
+	{
+	iTransientChangeDefinition->AddL(aId, aType, aViewIndex);
+	}
+
+void CLogServViewChangeManager::ChangeTransactionCommitL()
+	{
+	// We can only tell the client-side view change observer about the changes if:
+	//
+	// (2) we actually have something to tell the client views (some changes)
+	// (3) we have an outstanding client-side change message pointer
+	//
+	const TInt count = iTransientChangeDefinition->Count();
+	if	(count > 0) // (2)
+		{
+		// Do we have any existing pending changes? We can't alter the contents of the
+		// first pending change, since the client may already be preparing a client-side
+		// buffer of the requisite size. We can, however, combine the 2nd batch of changes
+		// with this new set so there is less IPC required (although more memory).
+		const TInt pendingChangeCount = iPendingChanges.Count();
+		if	(pendingChangeCount >= 2)
+			{
+			CLogChangeDefinition* changeDef = CLogChangeDefinition::NewL();
+			CleanupStack::PushL(changeDef);
+			//
+			CBufBase* buffer = iPendingChanges[1];
+			RBufReadStream readStream(*buffer);
+			//
+			readStream >> *changeDef;
+			
+			// Add new changes
+			TLogId logId = KLogNullId;
+			TLogDatabaseChangeType type = ELogChangeTypeUndefined;
+			TInt viewIndex = 0;
+			//
+			for(TInt i=0; i<count; i++)
+				{
+				type = iTransientChangeDefinition->At(i, logId, viewIndex);
+				changeDef->AddL(logId, type, viewIndex);
+				}
+
+			// Write the whole lot out again
+			buffer->Delete(0, buffer->Size());
+
+			RBufWriteStream writeStream(*buffer);
+			writeStream << *changeDef;
+			buffer->Compress();
+			CleanupStack::PopAndDestroy(changeDef);
+			}
+		else
+			{
+			CBufBase* buffer = CBufFlat::NewL(KLogServViewChangeBufferGranularity);
+			CleanupStack::PushL(buffer);
+
+			// Externalize changes
+			RBufWriteStream stream(*buffer);
+			stream << *iTransientChangeDefinition; 
+			buffer->Compress();
+
+			// Add to container
+			User::LeaveIfError(iPendingChanges.Append(buffer));
+			CleanupStack::Pop(buffer);
+			}
+
+		// Notify if necessary - handles (3) implicitly
+		NotifyClient();
+		}
+
+	// Free some memory
+	iTransientChangeDefinition->Reset();
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServViewChangeManager::DeliverChangesL(const RMessage2& aMessage)
+	{
+	if	(iPendingChanges.Count())
+		{
+		CBufBase* headItem = iPendingChanges[0];
+		//
+		const TInt expectedChangesSize = aMessage.Int1();
+		const TPtr8 pBufferContents(headItem->Ptr(0));
+
+		// Check buffer size is as we expect
+		if	(expectedChangesSize != pBufferContents.Size())
+			::PanicClientL(aMessage, ELogViewBadClientSideChangeBufferSize);
+		else
+			{
+			// Write back to client-side
+			aMessage.WriteL(2, pBufferContents);
+
+			// Remove the item
+			iPendingChanges.Remove(0);
+			delete headItem;
+			}
+		}
+	else
+		::PanicClientL(aMessage, ELogViewNoPendingChangesToDeliver);
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServViewChangeManager::RequestChangeNotifications(const RMessage2& aMessage)
+	{
+    if	(iClientSideChangeMessage == RMessagePtr2())
+		{
+		// Notify if we have any cached changes...
+		iClientSideChangeMessage = aMessage;
+		NotifyClient();
+		}
+	else
+		PanicClient(aMessage, ELogViewChangeRequestAlreadyIssued);
+	}
+
+void CLogServViewChangeManager::RequestChangeNotificationsCancel()
+	{
+    if	(iClientSideChangeMessage != RMessagePtr2())
+		CompleteClientChangeMessage(KErrCancel);
+
+	// Zap all the pending changes too
+	iPendingChanges.ResetAndDestroy();
+	iPendingChanges.GranularCompress();
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CLogServViewChangeManager::NotifyClient()
+	{
+	const TInt count = iPendingChanges.Count();
+    if	(iClientSideChangeMessage != RMessagePtr2() && count)
+		{
+		CBufBase* headItem = iPendingChanges[0];
+		const TInt messageSize = headItem->Size();
+		CompleteClientChangeMessage(messageSize);
+		}
+	}
+
+void CLogServViewChangeManager::CompleteClientChangeMessage(TInt aCompletionCode)
+	{
+	__ASSERT_ALWAYS(iClientSideChangeMessage != RMessagePtr2(), Panic(ELogViewNoClientChangeMessageOutstanding));
+	iClientSideChangeMessage.Complete(aCompletionCode);
+	}