webengine/osswebengine/cache/src/HttpCacheFileWriteHandler.cpp
changeset 10 a359256acfc6
child 11 c8a366e56285
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/cache/src/HttpCacheFileWriteHandler.cpp	Thu Aug 27 07:44:59 2009 +0300
@@ -0,0 +1,545 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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:  Implementation of CHttpCacheFileWriteHandler
+*
+*/
+
+// INCLUDE FILES
+#include "HttpCacheFileWriteHandler.h"
+#include "HttpCacheEntry.h"
+#include "HttpCacheHandler.h"
+#include "HttpCacheStreamHandler.h"
+#include "HttpCachePostponeWriteUtilities.h"
+#include "HttpCacheUtil.h"
+#include <HttpCacheManagerInternalCRKeys.h>
+#include <centralrepository.h>
+#include <hal.h>
+#include <f32file.h>
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+const TInt KMaxCollectCount = 5;    // collect a max of 5 items.
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+void CHttpCacheFileWriteHandler::OutputQueueContentToDebug()
+    {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:  %d objects on queue. Contents:"), iObjectQueue.Count());
+    TBuf<80> txt;
+    TInt totalSize=0;
+    for(TInt tmploop = 0; tmploop <iObjectQueue.Count(); tmploop++)
+        {
+        CHttpCacheEntry* entry = iObjectQueue[tmploop];
+        txt.Format(_L("CACHEPOSTPONE:    %d:  %d bytes - Cache:%08x -"), tmploop, entry->BodySize(), entry );
+        totalSize+=entry->BodySize();
+        HttpCacheUtil::WriteUrlToLog( 0, txt, entry->Url() );
+        }
+    HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:    %d bytes cached"), totalSize);
+#endif
+    }
+
+// FORWARD DECLARATIONS
+
+// ============================ MEMBER FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::CHttpCacheFileWriteHandler
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CHttpCacheFileWriteHandler::CHttpCacheFileWriteHandler(CHttpCacheHandler* aHandler, CHttpCacheStreamHandler* aStreamHandler, RFs& aRfs)
+    : CActive(EPriorityHigh),
+      iCacheHandler( aHandler ),
+      iCacheStreamHandler(aStreamHandler),
+      iFs(aRfs)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::ConstructL(const TInt aWriteTimeout)
+    {
+    iObjectQueue.Reset();
+    iObjectQueue.ReserveL(32);
+
+    iWaitTimer = CHttpCacheWriteTimeout::NewL( aWriteTimeout );
+    CActiveScheduler::Add(this);
+
+    MemoryManager::AddCollector(this);
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CHttpCacheFileWriteHandler* CHttpCacheFileWriteHandler::NewL(CHttpCacheHandler* aHandler, CHttpCacheStreamHandler* aStreamHandler, RFs& aRfs, const TInt aWriteTimeout)
+    {
+    CHttpCacheFileWriteHandler* self = new( ELeave ) CHttpCacheFileWriteHandler(aHandler, aStreamHandler, aRfs);
+
+    CleanupStack::PushL( self );
+    self->ConstructL(aWriteTimeout);
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CHttpCacheFileWriteHandler::~CHttpCacheFileWriteHandler()
+    {
+    Cancel();
+
+    DumpAllObjects();
+
+    if ( iWaitTimer )
+        {
+        iWaitTimer->Cancel();
+        delete iWaitTimer;
+        }
+
+    MemoryManager::RemoveCollector( this );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::DumpAllObjectsL
+// Emergency method - write everything to disk synchronously.
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::DumpAllObjects()
+    {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: >>FileWriteHandler::DumpAllObjects"));
+    OutputQueueContentToDebug();
+#endif
+    for ( TInt i=0; i < iObjectQueue.Count(); i++ )
+        {
+        iCacheStreamHandler->Flush(*iObjectQueue[i]);
+        }
+        iObjectQueue.Reset();
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: <<FileWriteHandler::DumpAllObjects"));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::CompareHttpCacheEntrySize
+// -----------------------------------------------------------------------------
+//
+TInt CHttpCacheFileWriteHandler::CompareHttpCacheEntrySize( const CHttpCacheEntry& aFirst, const CHttpCacheEntry& aSecond )
+    {
+    TInt first = aFirst.BodySize();
+    TInt second = aSecond.BodySize();
+
+    if ( first > second )
+        {
+        return -1;
+        }
+
+    if ( second > first )
+        {
+        return 1;
+        }
+
+    return 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::CollectMemory
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::CollectMemory(TUint aRequired)
+    {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE: >>FileWriteHandler::CollectMemory looking for %d bytes"), aRequired);
+    OutputQueueContentToDebug();
+#endif
+    if ( !iObjectQueue.Count() )
+        {
+        return;
+        }
+
+    TInt count = KMaxCollectCount;
+    while ( aRequired && count && iObjectQueue.Count() )
+        {
+        count--;
+        CHttpCacheEntry* entry = iObjectQueue[0];
+        iObjectQueue.Remove(0);
+        TInt size = entry->BodySize();
+        iCacheStreamHandler->Flush(*entry);
+        aRequired -= size;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::AddEntry
+// -----------------------------------------------------------------------------
+//
+TInt CHttpCacheFileWriteHandler::AddEntry(TAddStatus &aAddStatus, CHttpCacheEntry* aEntry)
+    {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: >>FileWriteHandler::AddEntry"));
+#endif
+
+    if ( iImmediateWriteThreshold && ( aEntry->BodySize() <= iImmediateWriteThreshold ) )
+        {
+        aAddStatus = EBodySmallerThanThreshold;
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE:   File smaller than minimum"));
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: <<FileWriteHandler::AddEntry"));
+#endif
+        return KErrNone;
+        }
+
+    // only ask about available system memory, deliberately conservative.
+    TInt freeMem;
+    HAL::Get(HALData::EMemoryRAMFree, freeMem);
+
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:  %d free memory (according to HAL)"), freeMem);
+#endif
+
+    if ( freeMem < iFreeRamThreshold )
+        {
+        aAddStatus = ENotEnoughFreeMemory;
+#ifdef __CACHELOG__
+        HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE:   Not enough spare RAM to postpone"));
+        HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: <<FileWriteHandler::AddEntry"));
+#endif
+        iLowMemoryState = ETrue;
+
+        if ( iWaitTimer->IsActive() )
+            {
+            // we have some items queued for write, begin to flush them since we're going to run out of memory soon anyway.
+            iWaitTimer->Cancel();
+            BeginWriting();
+            }
+
+        return KErrNone;
+        }
+
+    // if we get here, we're not in low memory state any more.
+    iLowMemoryState = EFalse;
+
+    // add entry to queue
+    TInt err = iObjectQueue.InsertInOrderAllowRepeats(aEntry, TLinearOrder<CHttpCacheEntry>(CompareHttpCacheEntrySize));
+
+    #ifdef __CACHELOG__
+    HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE: CHttpCacheFileWriteHandler: Added object %08x to postpone queue."), aEntry);
+    OutputQueueContentToDebug();
+#endif
+
+    // reset timer
+    if ( err == KErrNone )
+        {
+        aAddStatus = EAddedOk;
+        iWaitTimer->Start( CHttpCacheFileWriteHandler::WriteTimeout, this );
+        }
+    else
+        {
+        aAddStatus = ECheckReturn;
+        }
+
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: <<FileWriteHandler::AddEntry"));
+#endif
+
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::RemoveEntry
+// -----------------------------------------------------------------------------
+//
+CHttpCacheEntry* CHttpCacheFileWriteHandler::RemoveEntry(CHttpCacheEntry *aEntry)
+    {
+    CHttpCacheEntry *entry = aEntry;
+
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE: >>FileWriteHandler::RemoveEntry called for entry %08x"), aEntry);
+#endif
+
+    // take object off list.
+    if ( aEntry == iObjectFlushing && IsActive() )
+        {
+#ifdef __CACHELOG__
+        HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE: CHttpCacheFileWriteHandler::RemoveEntry - entry %08x is currently being written. Returning 'not found'."), aEntry);
+#endif
+        // the object will be removed from the list when it's done writing out, so we don't need to worry about it
+        entry = 0;
+        // back off from flushing anything else for a bit in case we want that as well..
+        iWaitTimer->Start(CHttpCacheFileWriteHandler::WriteTimeout, this);
+        }
+    else
+        {
+#ifdef __CACHELOG__
+        HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE: CHttpCacheFileWriteHandler::RemoveEntry - entry %08x not active."), aEntry);
+#endif
+        TInt index = iObjectQueue.Find( aEntry );
+        if ( index >= 0 )
+            {
+            iObjectQueue.Remove( index );
+            if ( !iObjectQueue.Count() )
+                {
+#ifdef __CACHELOG__
+                HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: CHttpCacheFileWriteHandler::RemoveEntry - nothing left on list, stopping timer."));
+#endif
+                // nothing on the list, so stop the timer.
+                iWaitTimer->Cancel();
+                }
+            }
+        }
+
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: <<FileWriteHandler::RemoveEntry"));
+#endif
+
+    return entry;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::RemoveAll
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::RemoveAll()
+    {
+    // empty list - note that HttpCacheEntries aren't owned.
+    iObjectQueue.Reset();
+    // stop us if we're active
+    Cancel();
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::WriteTimeout
+// -----------------------------------------------------------------------------
+//
+TInt CHttpCacheFileWriteHandler::WriteTimeout(TAny* aObject)
+    {
+    CHttpCacheFileWriteHandler *obj = (CHttpCacheFileWriteHandler *)aObject;
+
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: FileWriteHandler::WriteTimeout expired"));
+#endif
+
+    obj->BeginWriting();
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::BeginWriting
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::BeginWriting()
+    {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: >>FileWriteHandler::BeginWriting"));
+#endif
+
+    if ( !IsActive() )
+        {
+#ifdef __CACHELOG__
+        HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:   Setting FileWriteHandler %08x to active."), this);
+#endif
+        iStatus = KRequestPending;
+        SetActive();
+        TRequestStatus *stat = &iStatus;
+        User::RequestComplete(stat, KErrNone);
+        }
+#ifdef __CACHELOG__
+    else
+        {
+        HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:   FileWriteHandler %08x already active!"), this);
+        }
+
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: <<FileWriteHandler::BeginWriting"));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::DoCancel()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::RunL
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::RunL()
+    {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: >>FileWriteHandler::RunL"));
+    OutputQueueContentToDebug();
+#endif
+
+    TInt result = iStatus.Int();
+
+    // first, see if we have been writing anything
+    if ( iObjectFlushing )
+        {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE:     iObjectFlushing set, been writing something."));
+#endif
+
+        // should always be first item, find just in case...
+        TInt index = iObjectQueue.Find(iObjectFlushing);
+
+#ifdef __CACHELOG__
+        if ( index < 0 )
+            HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:     iObjectFlushing (%08x) not found in object queue!"), iObjectFlushing);
+#endif
+
+        if ( index >= 0 )
+            {
+#ifdef __CACHELOG__
+            HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:    iObjectFlushing (%08x) is at position %d in list"), iObjectFlushing, index);
+#endif
+            // the object might not exist in the queue.. how can this happen?
+            iObjectQueue.Remove(index);
+            //
+            if ( result != KErrNone )
+                {
+#ifdef __CACHELOG__
+                HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:     FileWriteHandler::RunL Failure while writing object %08x"), iObjectFlushing);
+#endif
+                // write failed.  Clean up this entry.
+                // first, remove it from the cache handler so that we won't try to reuse a dead entry
+                iCacheHandler->RemoveL( iObjectFlushing->Url() );
+                }
+            }
+        iObjectFlushing = 0;
+        }
+
+    // next, check to see if we've added anything to the cache while we've been writing out.
+    TInt count = iObjectQueue.Count();
+    if ( iWaitTimer->IsActive() )
+        {
+#ifdef __CACHELOG__
+        HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE:     FileWriteHandler::RunL New entry detected on postpone queue, wait for timeout again."));
+#endif
+        // something has been added to the queue, back off until it completes.
+        // this case intentionally left blank...
+        }
+    else
+        {
+        // remove any items from the top of the queue which have no body data.
+        while ( iObjectQueue.Count() && iObjectQueue[0]->BodySize() == 0 )
+            {
+            iObjectQueue.Remove(0);
+            };
+
+        // check to see if there is anything ready to write out
+        if ( iObjectQueue.Count() )
+            {
+            SetActive();
+            iStatus = KRequestPending;
+            iCacheStreamHandler->FlushAsync( *iObjectQueue[0], iStatus );
+            iObjectFlushing = iObjectQueue[0];
+#ifdef __CACHELOG__
+            HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:     FileWriteHandler::RunL continue cache flush, Starting object %08x."), iObjectFlushing);
+#endif
+            }
+        else
+            {   // nothing left to write, go idle.
+    #ifdef __CACHELOG__
+            HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE:     FileWriteHandler::RunL complete with nothing else to write."));
+    #endif
+            iCacheHandler->SaveLookupTableL();
+            iLowMemoryState = EFalse;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::Collect
+// -----------------------------------------------------------------------------
+//
+TUint CHttpCacheFileWriteHandler::Collect(TUint aRequired)
+    {
+#ifdef __CACHELOG__
+    HttpCacheUtil::WriteFormatLog(0, _L("CACHEPOSTPONE:  >>FileWriteHandler::Collect on FileWriteHandler %08x (low memory collector)"), this);
+#endif
+    if ( iWaitTimer->IsActive() )
+        {
+#ifdef __CACHELOG__
+        HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE:    Wait timer is active, cancel it and call DumpAllObjects"));
+#endif
+
+        iWaitTimer->Cancel();
+        CollectMemory( aRequired );
+        iLowMemoryState = ETrue;
+        BeginWriting();
+        }
+#ifdef __CACHELOG__
+    else
+        {
+        HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE:    Wait timer not active."));
+        }
+    HttpCacheUtil::WriteLog(0, _L("CACHEPOSTPONE: <<FileWriteHandler::Collect"));
+#endif
+    return 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::Restore
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheFileWriteHandler::Restore()
+    {
+    // not supported
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::Priority
+// -----------------------------------------------------------------------------
+//
+TOOMPriority CHttpCacheFileWriteHandler::Priority()
+    {
+    return EOOM_PriorityLow;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheFileWriteHandler::IsCacheEntryPostponed
+// -----------------------------------------------------------------------------
+//
+TBool CHttpCacheFileWriteHandler::IsCacheEntryPostponed(const CHttpCacheEntry* aEntry)
+    {
+    TInt index = iObjectQueue.Find( aEntry );
+
+    if ( index >= 0 )
+        {
+        return ETrue;
+        }
+
+    return EFalse;
+    }
+
+//  End of File