//******************************************** // AE_PCSA.cpp // ------------------------------------------- // Function implementations of the AE specialized // PCSA module // // Author: Leiwen Deng // Date: 12/10/2005 //******************************************** #include "AE_PCSA.h" //******************************************** // PCSA_MAIN() // ------------------------------------------- // The constructor //******************************************** PCSA_MAIN::PCSA_MAIN( void ) : pcsa_table( INITIAL_TABLE_SIZE, HashMD5 ) {} //******************************************** // ~PCSA_MAIN() // ------------------------------------------- // The destructor //******************************************** PCSA_MAIN::~PCSA_MAIN( void ) {} //******************************************** // pcsa_record = ReferenceEntry( md5key, client_ip, refcount ) // ------------------------------------------- // Denote a new reference to an entry. // Every time an entry is referred, the PCSA // module updates the corresponding record if // it exists // specifies the key of the entry // specifies the ip address of // current client that request this entry // is the reference count maintained // by SQUID // Return the pointer to the corresponding record // if it exists and is valid // Return NULL if the record does not exist or it // is invalid //******************************************** PCSA_RECORD * PCSA_MAIN::ReferenceEntry( const MD5_KEY &md5key, uint32 client_ip, u_short refcount ) { PCSA_RECORD * pcsa_record = pcsa_table.Find( md5key ); if ( pcsa_record ) { if ( refcount < refcount_threshold ) { // This entry seems to have been released by SQUID already but the release message has not been catched by AE // This is a rare case, but might occur when the pipe between SQUID and AE overflows pcsa_table.Delete( md5key ); return NULL; } } if ( refcount >= refcount_threshold ) { // Counting should start if ( ! pcsa_record ) { // Record entry is not found, insert a new entry to 'pcsa_table' PCSA_RECORD temp; pcsa_table.Insert( md5key, temp ); pcsa_record = pcsa_table.Find( md5key ); } if ( pcsa_record ) { if ( ! pcsa_record->ac_set && ! pcsa_record->pcsa ) { // Counting has not yet started, start it pcsa_record->ac_set = new AC_SET; } if ( pcsa_record->ac_set ) { // Accurate counting is still working, probabilistic counting has not yet started if ( pcsa_record->ac_set->size() >= max_ac_set_size ) { // Migrate accurate counting to probabilistic counting ACtoPC( pcsa_record ); } else { // Update accurate counting record pcsa_record->ac_set->insert( client_ip ); } } if ( pcsa_record->pcsa ) { // Probabilistic counting has started // Update probabilistic counting record pcsa_record->pcsa->InputValue( &client_ip ); } pcsa_record->squid_refcount = refcount; pcsa_record->refcount ++; return pcsa_record; } } return NULL; } //******************************************** // ACtoPC( pcsa_record ) // ------------------------------------------- // Transit a record from accurate counting to // probabilistic counting. // points to the record //******************************************** void PCSA_MAIN::ACtoPC( PCSA_RECORD * pcsa_record ) { if ( ! pcsa_record->ac_set || pcsa_record->pcsa ) return; pcsa_record->pcsa = new PCSA( m_bit, IP_Hash ); for ( AC_SET::iterator i = pcsa_record->ac_set->begin(); i != pcsa_record->ac_set->end(); ++ i ) { uint32 client_ip = *i; pcsa_record->pcsa->InputValue( &client_ip ); } delete pcsa_record->ac_set; pcsa_record->ac_set = NULL; } //******************************************** // DumpTable( operation ) // ------------------------------------------- // Dump the content of the hash table to a file. // specifies the option of dumping. //******************************************** void PCSA_MAIN::DumpTable( int operation ) const { FILE * fp; const char * dump_file = TABLE_DUMP_FILE_NAME; if( ( fp = fopen( dump_file, "w" ) ) == NULL ) fprintf ( stderr, "Error opening file \"%s\" for writing\n", dump_file ); else { if ( operation == SHOW_TABLE_STRUCTURE ) pcsa_table.ShowTableStructure( fp ); else pcsa_table.ShowTable( fp ); fclose( fp ); } } //******************************************** // true/false = Positive( pcsa_record ) // ------------------------------------------- // Check whether a record is "positive" according // to the detection rule //******************************************** bool PCSA_MAIN::Positive( const PCSA_RECORD * pcsa_record ) const { int cardinality = pcsa_record->Cardinality(); if ( cardinality < 100 ) { if ( (double)pcsa_record->refcount / (double)cardinality > positive_threshold ) return true; } return false; } //******************************************** // true/false = DeleteEntry( key ) // ------------------------------------------- // Delete an entry from the hash table. // specifies the key of the entry to // delete // Return "false" if the entry does not exist, // otherwise return "true". //******************************************** bool PCSA_MAIN::DeleteEntry( const MD5_KEY &key ) { return pcsa_table.Delete( key ); }