|
|
/******************************************************************************
Copyright (c) 1999-2000 Microsoft Corporation
Module Name: Cache.cpp
Abstract: Handles caching of database lookups.
Revision History:
******************************************************************************/
#include "stdafx.h"
////////////////////////////////////////////////////////////////////////////////
static const DWORD l_dwVersion = 0x01314351; // QC1 01
static const DWORD l_dwSizeThresholdHIGH = 2048*1024; static const DWORD l_dwSizeThresholdLOW = 1024*1024;
static const DATE l_dSaveThreshold = (60.0/86400.0); // 60 seconds.
static const WCHAR l_szBase [] = HC_ROOT_HELPSVC_CONFIG L"\\Cache"; static const WCHAR l_szIndex [] = L"Directory.bin"; static const WCHAR l_szQuery [] = L"Query_%08x.bin"; static const WCHAR l_szBackup[] = L".bak";
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
HRESULT Taxonomy::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ Taxonomy::Cache::NodeEntry& val ) { __HCP_FUNC_ENTRY( "Taxonomy::operator>> Taxonomy::Cache::NodeEntry" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_rs_data );
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const Taxonomy::Cache::NodeEntry& val ) { __HCP_FUNC_ENTRY( "Taxonomy::operator<< Taxonomy::Cache::NodeEntry" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_rs_data );
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
Taxonomy::Cache::NodeEntry::NodeEntry() { m_rs_data.m_ID_parent = -1; m_rs_data.m_ID_node = -1; }
bool Taxonomy::Cache::NodeEntry::operator<( /*[in]*/ NodeEntry const &en ) const { long lCmp = (m_rs_data.m_ID_parent - en.m_rs_data.m_ID_parent);
if(lCmp == 0) { lCmp = MPC::StrICmp( m_rs_data.m_strEntry, en.m_rs_data.m_strEntry ); }
return (lCmp < 0); }
bool Taxonomy::Cache::NodeEntry::operator==( /*[in]*/ long ID ) const { return m_rs_data.m_ID_node == ID; }
Taxonomy::Cache::NodeEntry::MatchNode::MatchNode( /*[in]*/ long ID ) { m_ID = ID; // long m_ID;
}
bool Taxonomy::Cache::NodeEntry::MatchNode::operator()( /*[in]*/ Taxonomy::Cache::NodeEntry const &en ) const { return en == m_ID; }
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
HRESULT Taxonomy::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ Taxonomy::Cache::QueryEntry& val ) { __HCP_FUNC_ENTRY( "Taxonomy::operator>> Taxonomy::Cache::QueryEntry" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_strID ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iType ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iSequence ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_fNull );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_dwSize ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_dLastUsed );
val.m_fRemoved = false;
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const Taxonomy::Cache::QueryEntry& val ) { __HCP_FUNC_ENTRY( "Taxonomy::operator<< Taxonomy::Cache::QueryEntry" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_strID ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iType ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iSequence ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_fNull );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_dwSize ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_dLastUsed );
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
Taxonomy::Cache::QueryEntry::QueryEntry() { // MPC::wstring m_strID;
m_iType = OfflineCache::ET_INVALID; // int m_iType;
m_iSequence = 0; // int m_iSequence;
m_fNull = true; // bool m_fNull;
//
m_dwSize = 0; // DWORD m_dwSize;
m_dLastUsed = 0; // DATE m_dLastUsed;
m_fRemoved = true; // bool m_fRemoved;
}
bool Taxonomy::Cache::QueryEntry::operator<( /*[in]*/ QueryEntry const &en ) const { int iCmp = MPC::StrCmp( m_strID, en.m_strID );
if(iCmp == 0) { iCmp = (m_iType - en.m_iType); }
return (iCmp < 0); }
////////////////////////////////////////
void Taxonomy::Cache::QueryEntry::Touch() { m_dLastUsed = MPC::GetLocalTime(); m_fRemoved = false; }
HRESULT Taxonomy::Cache::QueryEntry::GetFile( /*[out]*/ MPC::wstring& strFile ) { WCHAR rgTmp[64]; swprintf( rgTmp, l_szQuery, m_iSequence );
strFile = rgTmp;
return S_OK; }
////////////////////////////////////////
HRESULT Taxonomy::Cache::QueryEntry::Store( /*[in]*/ MPC::StorageObject& disk , /*[in]*/ const CPCHQueryResultCollection* pColl ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::QueryEntry::Store" );
HRESULT hr; MPC::StorageObject* child; MPC::wstring strFile;
__MPC_EXIT_IF_METHOD_FAILS(hr, GetFile( strFile ));
m_fNull = (pColl->Size() == 0);
__MPC_EXIT_IF_METHOD_FAILS(hr, disk.GetChild( strFile.c_str(), child, STGM_READWRITE, (m_fNull == false) ? STGTY_STREAM : 0 )); if(m_fNull == false) { if(child) { CComPtr<IStream> stream;
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream )); if(stream) { STATSTG statstg;
__MPC_EXIT_IF_METHOD_FAILS(hr, pColl->SaveToCache( stream ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->Stat( &statstg, STATFLAG_NONAME )); m_dwSize = statstg.cbSize.LowPart; } } } else { if(child) { __MPC_EXIT_IF_METHOD_FAILS(hr, child->Delete()); } }
Touch(); hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::QueryEntry::Retrieve( /*[in]*/ MPC::StorageObject& disk , /*[in]*/ CPCHQueryResultCollection* pColl ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::QueryEntry::Retrieve" );
HRESULT hr;
if(m_fNull == false) { MPC::StorageObject* child; MPC::wstring strFile;
__MPC_EXIT_IF_METHOD_FAILS(hr, GetFile( strFile ));
__MPC_EXIT_IF_METHOD_FAILS(hr, disk.GetChild( strFile.c_str(), child, STGM_READWRITE, 0 )); if(child) { CComPtr<IStream> stream;
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream )); if(stream) { __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->LoadFromCache( stream )); } } }
Touch(); hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::QueryEntry::Release( /*[in]*/ MPC::StorageObject& disk ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::QueryEntry::Release" );
HRESULT hr;
if(m_fNull == false) { MPC::StorageObject* child; MPC::wstring strFile;
__MPC_EXIT_IF_METHOD_FAILS(hr, GetFile( strFile ));
__MPC_EXIT_IF_METHOD_FAILS(hr, disk.GetChild( strFile.c_str(), child, STGM_READWRITE, 0 )); if(child) { __MPC_EXIT_IF_METHOD_FAILS(hr, child->Delete()); } }
m_fRemoved = true; hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool Taxonomy::Cache::SortEntries::operator()( /*[in]*/ QueryEntry* const &left, /*[in]*/ QueryEntry* const &right ) const { return (left->m_dLastUsed < right->m_dLastUsed); }
////////////////////////////////////////////////////////////////////////////////
//
// ITSS.DLL is broken under IA64....
//
#ifdef _IA64_
#define CACHEDHELPSET_STORAGETOUSE false
#else
#define CACHEDHELPSET_STORAGETOUSE true
#endif
Taxonomy::Cache::CachedHelpSet::CachedHelpSet() : m_disk( STGM_READWRITE, /*fITSS*/CACHEDHELPSET_STORAGETOUSE ) { Init(); }
Taxonomy::Cache::CachedHelpSet::~CachedHelpSet() { if(m_fDirty) { (void)EnsureInSync( true ); }
//
// Copy working file as the backup.
//
if(m_fLoaded) { MPC::wstring strFileBack = m_strFile; strFileBack += l_szBackup;
if(SUCCEEDED(m_disk.Compact())) { (void)MPC::MoveFile( m_strFile, strFileBack ); } } }
Taxonomy::Cache::CachedHelpSet::CachedHelpSet( /*[in]*/ const CachedHelpSet& chs ) : m_disk( STGM_READWRITE, /*fITSS*/CACHEDHELPSET_STORAGETOUSE ) { Init();
m_ths = chs.m_ths; // Taxonomy::HelpSet m_ths;
m_strFile = chs.m_strFile; // MPC::wstring m_strFile;
// MPC::StorageObject m_disk;
//
// bool m_fLoaded;
// bool m_fDirty;
// bool m_fMarkedForLoad;
// DATE m_dLastSaved;
// long m_lTopNode;
// NodeEntrySet m_setNodes;
// QueryEntrySet m_setQueries;
// int m_iLastSequence;
}
Taxonomy::Cache::CachedHelpSet& Taxonomy::Cache::CachedHelpSet::operator=( /*[in]*/ const CachedHelpSet& chs ) { Clean();
m_ths = chs.m_ths; // Taxonomy::HelpSet m_ths;
m_strFile = chs.m_strFile; // MPC::wstring m_strFile;
// MPC::StorageObject m_disk;
//
// bool m_fLoaded;
// bool m_fDirty;
// bool m_fMarkedForLoad;
// DATE m_dLastSaved;
// long m_lTopNode;
// NodeEntrySet m_setNodes;
// QueryEntrySet m_setQueries;
// int m_iLastSequence;
return *this; }
bool Taxonomy::Cache::CachedHelpSet::operator<( /*[in]*/ CachedHelpSet const &hs ) const { return m_ths < hs.m_ths; }
////////////////////////////////////////////////////////////////////////////////
void Taxonomy::Cache::CachedHelpSet::Init() { // Taxonomy::HelpSet m_ths;
// MPC::wstring m_strFile;
// MPC::StorageObject m_disk;
//
m_fLoaded = false; // bool m_fLoaded;
m_fDirty = false; // bool m_fDirty;
m_fMarkedForLoad = false; // bool m_fMarkedForLoad;
m_dLastSaved = 0; // DATE m_dLastSaved;
m_lTopNode = -1; // long m_lTopNode;
// NodeEntrySet m_setNodes;
// QueryEntrySet m_setQueries;
m_iLastSequence = 1; // int m_iLastSequence;
}
void Taxonomy::Cache::CachedHelpSet::Clean() { // Taxonomy::HelpSet m_ths;
// MPC::wstring m_strFile;
m_disk.Release(); // MPC::StorageObject m_disk;
//
m_fLoaded = false; // bool m_fLoaded;
m_fDirty = false; // bool m_fDirty;
// DATE m_dLastSaved;
m_lTopNode = -1; // long m_lTopNode;
m_setNodes .clear(); // NodeEntrySet m_setNodes;
m_setQueries .clear(); // QueryEntrySet m_setQueries;
m_iLastSequence = 1; // int m_iLastSequence;
}
HRESULT Taxonomy::Cache::CachedHelpSet::Load() { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::Load" );
HRESULT hr; MPC::StorageObject* child;
Clean();
DEBUG_AppendPerf( DEBUG_PERF_CACHE_L1, "Loading Taxonomy Cache" );
//
// Copy the backup on top of the working file.
//
{ MPC::wstring strFileBack = m_strFile; strFileBack += l_szBackup;
(void)MPC::DeleteFile( m_strFile ); (void)MPC::CopyFile ( strFileBack, m_strFile ); }
if(FAILED(m_disk.Exists())) { __MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.Create()); }
__MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.GetChild( l_szIndex, child, STGM_READWRITE, 0 )); if(child) { CComPtr<IStream> stream;
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream )); if(stream) { MPC::Serializer_IStream streamReal( stream ); MPC::Serializer_Buffering streamBuf ( streamReal ); DWORD dwVer;
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer ); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_iLastSequence); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_lTopNode ); DEBUG_AppendPerf( DEBUG_PERF_CACHE_L1, "Loading Taxonomy Cache : nodes" ); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_setNodes ); DEBUG_AppendPerf( DEBUG_PERF_CACHE_L1, "Loading Taxonomy Cache : queries" ); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_setQueries ); } } DEBUG_AppendPerf( DEBUG_PERF_CACHE_L1, "Loaded Taxonomy Cache" );
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(FAILED(hr)) Clean();
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::Save() { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::Save" );
HRESULT hr; MPC::StorageObject* child;
if(FAILED(m_disk.Exists())) { __MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.Create()); }
__MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.GetChild( l_szIndex, child, STGM_READWRITE, STGTY_STREAM )); if(child) { CComPtr<IStream> stream;
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream )); if(stream) { MPC::Serializer_IStream streamReal( stream ); MPC::Serializer_Buffering streamBuf ( streamReal );
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << l_dwVersion ); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_iLastSequence); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_lTopNode ); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_setNodes ); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_setQueries );
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf.Flush()); } }
#if 0
////////////////////////////////////////////////////////////////////////////////
//
// DEBUG CODE
//
{ USES_CONVERSION;
HHK::Writer writer; CHAR rgBuf[1024]; QueryEntryIter it; SortEntries Pr; SortedEntryVec vec; SortedEntryIter it2;
strFile += L".debug";
__MPC_EXIT_IF_METHOD_FAILS(hr, writer.Init( strFile.c_str() ));
for(it = m_setQueries.begin(); it != m_setQueries.end(); it++) { vec.push_back( &(*it) ); }
std::sort( vec.begin(), vec.end(), Pr );
for(it2 = vec.begin(); it2 != vec.end(); it2++) { QueryEntry* en = *it2;
sprintf( rgBuf, "%80s: %1d %3d %5d %1d %5.12g\n", W2A( en->m_strID.c_str() ), en->m_iType , en->m_iSequence , (int)en->m_dwSize , (int)en->m_fRemoved , en->m_dLastUsed );
__MPC_EXIT_IF_METHOD_FAILS(hr, writer.OutputLine( rgBuf )); } } //
// DEBUG CODE
//
////////////////////////////////////////////////////////////////////////////////
#endif
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::EnsureInSync( /*[in]*/ bool fForceSave ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::EnsureInSync" );
HRESULT hr;
if(m_fLoaded == false) { m_fDirty = false; m_disk = m_strFile.c_str();
__MPC_EXIT_IF_METHOD_FAILS(hr, Load());
m_dLastSaved = MPC::GetSystemTime(); m_fLoaded = true; }
if(m_fDirty) { DATE dNow = MPC::GetSystemTime();
if(fForceSave == false) { if(dNow - m_dLastSaved > l_dSaveThreshold) { fForceSave = true; } }
if(fForceSave) { __MPC_EXIT_IF_METHOD_FAILS(hr, Save());
m_dLastSaved = dNow; m_fDirty = false; } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////
HRESULT Taxonomy::Cache::CachedHelpSet::GenerateDefaultQueries( /*[in]*/ Taxonomy::Settings& ts , /*[in]*/ Taxonomy::Updater& updater , /*[in]*/ long ID , /*[in]*/ long lLevel ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::GenerateDefaultQueries" );
HRESULT hr; CComPtr<CPCHQueryResultCollection> coll; MPC::wstring strPath;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &coll ));
__MPC_EXIT_IF_METHOD_FAILS(hr, BuildNodePath( ID, strPath, /*fParent*/false ));
//
// Build the queries.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, updater.LookupNode ( strPath.c_str(), coll )); coll->Erase(); __MPC_EXIT_IF_METHOD_FAILS(hr, updater.LookupSubNodes ( strPath.c_str(), /*fVisibleOnly*/true, coll )); coll->Erase(); __MPC_EXIT_IF_METHOD_FAILS(hr, updater.LookupNodesAndTopics( strPath.c_str(), /*fVisibleOnly*/true, coll )); coll->Erase(); __MPC_EXIT_IF_METHOD_FAILS(hr, updater.LookupTopics ( strPath.c_str(), /*fVisibleOnly*/true, coll )); coll->Erase();
//
// Recurse for sub-levels.
//
if(lLevel++ < 3) { MatchSet res; MatchIter it;
__MPC_EXIT_IF_METHOD_FAILS(hr, LocateSubNodes( ID, /*fRecurse*/false, /*fOnlyVisible*/true, res ));
for(it=res.begin(); it!=res.end(); it++) { __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateDefaultQueries( ts, updater, *it, lLevel )); } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::GenerateDefaultQueries( /*[in]*/ Taxonomy::Settings& ts , /*[in]*/ Taxonomy::Updater& updater ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::GenerateDefaultQueries" );
HRESULT hr; static WCHAR* c_rgNodes[] = { L"", L"_SYSTEM_", L"UNMAPPED" };
for(int i=0; i<ARRAYSIZE(c_rgNodes); i++) { long id = m_lTopNode; MPC::WStringVector vec; MPC::WStringVectorIter it; NodeEntryIter it2;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SplitAtDelimiter( vec, c_rgNodes[i], L"/" ));
for(it = vec.begin(); it != vec.end(); it++) { if(!LocateNode( id, it->c_str(), it2 )) break;
id = it2->m_rs_data.m_ID_node; }
if(it == vec.end()) { __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateDefaultQueries( ts, updater, id, 0 )); } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::PrePopulate( /*[in]*/ Cache* parent ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::PrePopulate" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync());
//
// This opens the database, walks through all the nodes in the taxonomy and makes a copy in the cache.
//
DEBUG_AppendPerf( DEBUG_PERF_CACHE_L1, "PrePopulating Taxonomy Cache" ); { Taxonomy::Settings ts( m_ths ); JetBlue::SessionHandle handle; JetBlue::Database* db; Taxonomy::Updater updater; Taxonomy::RS_Taxonomy* rs; bool fFound;
__MPC_EXIT_IF_METHOD_FAILS(hr, ts.GetDatabase( handle, db, /*fReadOnly*/true )); __MPC_EXIT_IF_METHOD_FAILS(hr, updater.Init ( ts, db, parent ));
__MPC_EXIT_IF_METHOD_FAILS(hr, updater.GetTaxonomy( &rs ));
m_lTopNode = -1; m_setNodes.clear(); __MPC_EXIT_IF_METHOD_FAILS(hr, rs->Move( 0, JET_MoveFirst, &fFound )); while(fFound) { NodeEntry en;
en.m_rs_data = *rs; if(!en.m_rs_data.m_fValid__ID_parent) { en.m_rs_data.m_ID_parent = -1;
m_lTopNode = en.m_rs_data.m_ID_node; }
m_setNodes.insert( en );
__MPC_EXIT_IF_METHOD_FAILS(hr, rs->Move( 0, JET_MoveNext, &fFound )); }
m_fDirty = true; __MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync( true ));
DEBUG_AppendPerf( DEBUG_PERF_CACHE_L1, "PrePopulating Taxonomy Cache : Nodes done" );
//
// Walk through the first 3 level of nodes and pre-generate the queries.
//
// We disable offline flushing of the root index, because it gets changed too often...
//
__MPC_EXIT_IF_METHOD_FAILS(hr, OfflineCache::Root::s_GLOBAL->DisableSave( )); __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateDefaultQueries ( ts, updater )); __MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync ( true )); __MPC_EXIT_IF_METHOD_FAILS(hr, OfflineCache::Root::s_GLOBAL->EnableSave ( )); } DEBUG_AppendPerf( DEBUG_PERF_CACHE_L1, "PrePopulated Taxonomy Cache : Nodes done" );
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::Erase() { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::Erase" );
HRESULT hr;
Clean();
{ MPC::wstring strFileBack = m_strFile; strFileBack += l_szBackup;
(void)MPC::DeleteFile( m_strFile , /*fForce*/true, /*fDelayed*/false ); (void)MPC::DeleteFile( strFileBack, /*fForce*/true, /*fDelayed*/false ); }
//
// Propagate change to the offline cache.
//
{ OfflineCache::Handle handle;
if(SUCCEEDED(OfflineCache::Root::s_GLOBAL->Locate( m_ths, handle ))) { if(SUCCEEDED(handle->RemoveQueries())) { (void)OfflineCache::Root::s_GLOBAL->Flush(); } } }
hr = S_OK;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::PrepareToLoad() { m_fMarkedForLoad = true;
return S_OK; }
HRESULT Taxonomy::Cache::CachedHelpSet::LoadIfMarked() { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::LoadIfMarked" );
HRESULT hr;
if(m_fMarkedForLoad) { m_fMarkedForLoad = false;
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync());
//
// Load the JetBlue database.
//
{ Taxonomy::Settings ts( m_ths ); JetBlue::SessionHandle handle; JetBlue::Database* db;
__MPC_EXIT_IF_METHOD_FAILS(hr, ts.GetDatabase( handle, db, /*fReadOnly*/true )); } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::MRU() { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::MRU" );
HRESULT hr; QueryEntryIter it; DWORD dwSizeTot = 0;
//
// Get total cache size.
//
for(it = m_setQueries.begin(); it != m_setQueries.end(); it++) { if(it->m_fRemoved == false) { dwSizeTot += it->m_dwSize; } }
//
// If the total size of the cache is bigger than a certain value, start to purge from the least used query.
//
if(dwSizeTot > l_dwSizeThresholdHIGH) { SortEntries Pr; SortedEntryVec vec; SortedEntryIter it2;
for(it = m_setQueries.begin(); it != m_setQueries.end(); it++) { if(it->m_fRemoved == false) { vec.push_back( &(*it) ); } }
std::sort( vec.begin(), vec.end(), Pr );
for(it2 = vec.begin(); it2 != vec.end(); it2++) { QueryEntry* en = *it2;
__MPC_EXIT_IF_METHOD_FAILS(hr, en->Release( m_disk ));
m_fDirty = true; dwSizeTot -= en->m_dwSize;
if(dwSizeTot < l_dwSizeThresholdLOW) break; }
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////
bool Taxonomy::Cache::CachedHelpSet::LocateNode( /*[in] */ long ID_parent , /*[in] */ LPCWSTR szEntry , /*[out]*/ NodeEntryIter& it ) { NodeEntry en;
en.m_rs_data.m_ID_parent = ID_parent; en.m_rs_data.m_strEntry = SAFEWSTR(szEntry);
it = m_setNodes.find( en ); return (it != m_setNodes.end()); }
HRESULT Taxonomy::Cache::CachedHelpSet::LocateNode( /*[in] */ long ID_parent , /*[in] */ LPCWSTR szEntry , /*[out]*/ RS_Data_Taxonomy& rs_data ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::LocateNode" );
HRESULT hr; NodeEntryIter it;
rs_data.m_ID_node = -1;
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync());
if(LocateNode( ID_parent, szEntry, it ) == false) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); }
rs_data = it->m_rs_data;
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::LocateSubNodes( /*[in] */ long ID_node , /*[in] */ bool fRecurse , /*[in] */ bool fOnlyVisible , /*[out]*/ MatchSet& res ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::LocateSubNodes" );
HRESULT hr; NodeEntry en; NodeEntryIterConst it;
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync());
en.m_rs_data.m_ID_parent = ID_node;
it = m_setNodes.lower_bound( en ); while(it != m_setNodes.end() && it->m_rs_data.m_ID_parent == ID_node) { if(fOnlyVisible == false || it->m_rs_data.m_fVisible) { res.insert( it->m_rs_data.m_ID_node );
if(fRecurse) { __MPC_EXIT_IF_METHOD_FAILS(hr, LocateSubNodes( it->m_rs_data.m_ID_node, /*fRecurse*/true, fOnlyVisible, res )); } }
it++; }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::LocateNodesFromURL( /*[in] */ LPCWSTR szURL , /*[out]*/ MatchSet& res ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::LocateNodesFromURL" );
HRESULT hr; NodeEntryIterConst it;
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync());
for(it = m_setNodes.begin(); it != m_setNodes.end(); it++) { if(!MPC::StrICmp( szURL, it->m_rs_data.m_strDescriptionURI )) { res.insert( it->m_rs_data.m_ID_node ); } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::CachedHelpSet::BuildNodePath( /*[in] */ long ID , /*[out]*/ MPC::wstring& strPath , /*[in] */ bool fParent ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::BuildNodePath" );
HRESULT hr; NodeEntryIterConst it; MPC::wstring strTmp;
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync());
strTmp .reserve( 1024 ); strPath.reserve( 1024 );
strPath = L"";
while(ID != m_lTopNode) { NodeEntry::MatchNode cmp( ID );
it = std::find_if( m_setNodes.begin(), m_setNodes.end(), cmp ); if(it == m_setNodes.end()) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); }
if(fParent == false) { strTmp = it->m_rs_data.m_strEntry; if(strPath.size()) { strTmp += L"/"; strTmp += strPath; } strPath = strTmp; } else { fParent = true; }
ID = it->m_rs_data.m_ID_parent; }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////
HRESULT Taxonomy::Cache::CachedHelpSet::LocateQuery( /*[in] */ LPCWSTR szID , /*[in] */ int iType , /*[out]*/ QueryEntry* &pEntry , /*[in] */ bool fCreate ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::CachedHelpSet::LocateQuery" );
HRESULT hr; QueryEntry en; QueryEntryIter it;
pEntry = NULL;
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureInSync());
en.m_strID = SAFEWSTR(szID); en.m_iType = iType;
it = m_setQueries.find( en ); if(it == m_setQueries.end()) { if(fCreate == false) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); }
it = m_setQueries.insert( en ).first;
it->m_iSequence = m_iLastSequence++; } else { if(fCreate == false) { if(it->m_fRemoved) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); } } }
pEntry = &(*it); pEntry->m_fRemoved = false; m_fDirty = true; hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Taxonomy::Cache::Cache() { // CacheSet m_skus;
(void)MPC::_MPC_Module.RegisterCallback( this, (void (Taxonomy::Cache::*)())Shutdown ); }
Taxonomy::Cache::~Cache() { MPC::_MPC_Module.UnregisterCallback( this );
Shutdown(); }
////////////////////
Taxonomy::Cache* Taxonomy::Cache::s_GLOBAL( NULL );
HRESULT Taxonomy::Cache::InitializeSystem() { if(s_GLOBAL == NULL) { s_GLOBAL = new Taxonomy::Cache; }
return s_GLOBAL ? S_OK : E_OUTOFMEMORY; }
void Taxonomy::Cache::FinalizeSystem() { if(s_GLOBAL) { delete s_GLOBAL; s_GLOBAL = NULL; } }
////////////////////
void Taxonomy::Cache::Shutdown() { m_skus.clear(); }
HRESULT Taxonomy::Cache::Locate( /*[in] */ const Taxonomy::HelpSet& ths , /*[out]*/ CacheIter& it ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::Locate" );
HRESULT hr; CachedHelpSet hs; MPC::SmartLock<_ThreadModel> lock( this );
hs.m_ths = ths; it = m_skus.find( hs ); if(it == m_skus.end()) { WCHAR rgTmp[MAX_PATH]; _snwprintf( rgTmp, MAXSTRLEN(rgTmp), L"%s\\%s_%ld.dat", l_szBase, hs.m_ths.GetSKU(), hs.m_ths.GetLanguage() );
it = m_skus.insert( hs ).first;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SubstituteEnvVariables( it->m_strFile = rgTmp )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir ( it->m_strFile ));
it->m_fDirty = true; }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT Taxonomy::Cache::PrePopulate( /*[in]*/ const Taxonomy::HelpSet& ths ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::PrePopulate" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->PrePopulate( this ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::Erase( /*[in]*/ const Taxonomy::HelpSet& ths ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::Erase" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->Erase());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::PrepareToLoad( /*[in]*/ const Taxonomy::HelpSet& ths ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::PrepareToLoad" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->PrepareToLoad());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::LoadIfMarked( /*[in]*/ const Taxonomy::HelpSet& ths ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::LoadIfMarked" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->LoadIfMarked());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////
HRESULT Taxonomy::Cache::LocateNode( /*[in] */ const Taxonomy::HelpSet& ths , /*[in] */ long ID_parent , /*[in] */ LPCWSTR szEntry , /*[out]*/ RS_Data_Taxonomy& rs_data ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::LocateNode" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->LocateNode( ID_parent, szEntry, rs_data ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::LocateSubNodes( /*[in] */ const Taxonomy::HelpSet& ths , /*[in] */ long ID_node , /*[in] */ bool fRecurse , /*[in] */ bool fOnlyVisible , /*[out]*/ MatchSet& res ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::LocateSubNodes" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->LocateSubNodes( ID_node, fRecurse, fOnlyVisible, res ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::LocateNodesFromURL( /*[in] */ const Taxonomy::HelpSet& ths , /*[in] */ LPCWSTR szURL , /*[out]*/ MatchSet& res ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::LocateNodesFromURL" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->LocateNodesFromURL( szURL, res ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::BuildNodePath( /*[in] */ const Taxonomy::HelpSet& ths , /*[in] */ long ID , /*[out]*/ MPC::wstring& strPath , /*[in] */ bool fParent ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::BuildNodePath" );
HRESULT hr; CacheIter it; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->BuildNodePath( ID, strPath, fParent ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////
HRESULT Taxonomy::Cache::StoreQuery( /*[in]*/ const Taxonomy::HelpSet& ths , /*[in]*/ LPCWSTR szID , /*[in]*/ int iType , /*[in]*/ const CPCHQueryResultCollection* pColl ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::StoreQuery" );
HRESULT hr; CacheIter it; QueryEntry* pEntry; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pColl); __MPC_PARAMCHECK_END();
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->LocateQuery( szID, iType, pEntry, true ));
__MPC_EXIT_IF_METHOD_FAILS(hr, pEntry->Store( it->m_disk, pColl ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->MRU ()); __MPC_EXIT_IF_METHOD_FAILS(hr, it->EnsureInSync());
//
// Propagate change to the offline cache.
//
{ OfflineCache::Handle handle;
if(SUCCEEDED(OfflineCache::Root::s_GLOBAL->Locate( it->m_ths, handle ))) { if(handle->AreYouInterested( szID, iType )) { if(SUCCEEDED(handle->Store( szID, iType, pColl ))) { (void)OfflineCache::Root::s_GLOBAL->Flush(); } } } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT Taxonomy::Cache::RetrieveQuery( /*[in]*/ const Taxonomy::HelpSet& ths , /*[in]*/ LPCWSTR szID , /*[in]*/ int iType , /*[in]*/ CPCHQueryResultCollection* pColl ) { __HCP_FUNC_ENTRY( "Taxonomy::Cache::Retrieve" );
HRESULT hr; CacheIter it; QueryEntry* pEntry; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pColl); __MPC_PARAMCHECK_END();
__MPC_EXIT_IF_METHOD_FAILS(hr, Locate( ths, it ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->LocateQuery( szID, iType, pEntry, false ));
__MPC_EXIT_IF_METHOD_FAILS(hr, pEntry->Retrieve( it->m_disk, pColl ));
__MPC_EXIT_IF_METHOD_FAILS(hr, it->EnsureInSync());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
|