void CLibraryDictionary::BuildHashTable() { ASSUME_LOCK( Library.m_pSection ); if ( m_bValid ) return; if ( ! m_pTable ) { m_pTable = new CQueryHashTable(); if ( ! m_pTable ) return; m_pTable->Create(); } m_pTable->Clear(); // Add words to hash table //TRACE( L"[LD] Dictionary size: %d words\n", m_oWordMap.GetCount() ); //TRACE( L"[LD] Hash table size: %d\n", m_oWordMap.GetHashTableSize() ); for ( POSITION pos1 = m_oWordMap.GetStartPosition(); pos1; ) { CString strWord; CFileList* pList = NULL; m_oWordMap.GetNextAssoc( pos1, strWord, pList ); //TRACE( L"[LD] Word \"%hs\" found %d time(s) in %d file(s)\n", (LPCSTR)CT2A( strWord ), oWord.m_nCount, oWord.m_pList->GetCount() ); for ( POSITION pos2 = pList->GetHeadPosition(); pos2; ) { const CLibraryFile* pFile = pList->GetNext( pos2 ); // Check if the file can be uploaded if ( pFile->IsShared() ) { // Add the keyword to the table m_pTable->AddExactString( strWord ); break; } } } // Add sha1/ed2k hashes to hash table for ( POSITION pos = LibraryMaps.GetFileIterator(); pos; ) { const CLibraryFile* pFile = LibraryMaps.GetNextFile( pos ); // Check if the file can be uploaded if ( pFile->IsShared() ) m_pTable->AddHashes( *pFile ); } m_bValid = true; }
CFileList* CLibraryDictionary::Search(const CQuerySearch* pSearch, const int nMaximum, const bool bLocal, const bool bAvailableOnly) { ASSUME_LOCK( Library.m_pSection ); if ( ! m_bValid ) { BuildHashTable(); if ( ! m_bValid ) return NULL; } // Only check the hash when a search comes from other client. if ( ! bLocal && ! m_pTable->Check( pSearch ) ) return NULL; ++m_nSearchCookie; CLibraryFile* pHit = NULL; CQuerySearch::const_iterator pWordEntry = pSearch->begin(); const CQuerySearch::const_iterator pLastWordEntry = pSearch->end(); for ( ; pWordEntry != pLastWordEntry; ++pWordEntry ) { if ( pWordEntry->first[ 0 ] == L'-' ) continue; CString strWord( pWordEntry->first, static_cast< int >( pWordEntry->second ) ); CFileList* pList = NULL; if ( m_oWordMap.Lookup( strWord, pList ) ) { for ( POSITION pos = pList->GetHeadPosition(); pos; ) { CLibraryFile* pFile = pList->GetNext( pos ); if ( bAvailableOnly && ! pFile->IsAvailable() ) continue; if ( ! bLocal && ! pFile->IsShared() ) continue; if ( pFile->m_nSearchCookie == m_nSearchCookie ) { ++pFile->m_nSearchWords; } else { pFile->m_nSearchCookie = m_nSearchCookie; pFile->m_nSearchWords = 1; pFile->m_pNextHit = pHit; pHit = pFile; } } } } size_t nLowerBound = ( pSearch->tableSize() >= 3 ) ? ( pSearch->tableSize() * 2 / 3 ) : pSearch->tableSize(); CFileList* pHits = NULL; for ( ; pHit; pHit = pHit->m_pNextHit ) { ASSERT( pHit->m_nSearchCookie == m_nSearchCookie ); if ( pHit->m_nSearchWords < nLowerBound ) continue; if ( pSearch->Match( pHit->GetSearchName(), pHit->m_pSchema ? (LPCTSTR)pHit->m_pSchema->GetURI() : NULL, pHit->m_pMetadata, pHit ) ) { if ( ! pHits ) pHits = new CFileList; pHits->AddTail( pHit ); if ( ! bLocal ) { pHit->m_nHitsToday ++; pHit->m_nHitsTotal ++; } if ( pHit->m_nCollIndex ) { CLibraryFile* pCollection = LibraryMaps.LookupFile( pHit->m_nCollIndex, ! bLocal, bAvailableOnly ); if ( pCollection ) { if ( pCollection->m_nSearchCookie != m_nSearchCookie ) { pCollection->m_nSearchCookie = m_nSearchCookie; pHits->AddHead( pCollection ); } } else { // Collection removed without deleting indexes pHit->m_nCollIndex = 0ul; } } if ( nMaximum > 0 && pHits->GetCount() >= nMaximum ) break; } } return pHits; }