http://www.mediawiki.org/wiki/Special:Code/MediaWiki/66599

Revision: 66599
Author:   tstarling
Date:     2010-05-18 02:38:56 +0000 (Tue, 18 May 2010)

Log Message:
-----------
* Split off Session class from App.
* Reset sessions explicitly instead of using the shared_ptr destructor. 
Improves performance slightly by not copying shared_ptr's so often.
* Use a boost::pool for CacheEntry allocation. Doesn't really make any 
difference, may need to be reverted.

Modified Paths:
--------------
    trunk/tools/maxcache/App.cpp
    trunk/tools/maxcache/App.h
    trunk/tools/maxcache/Cache.cpp
    trunk/tools/maxcache/Cache.h
    trunk/tools/maxcache/CacheEntry.h
    trunk/tools/maxcache/Makefile
    trunk/tools/maxcache/typedefs.h

Added Paths:
-----------
    trunk/tools/maxcache/Session.cpp
    trunk/tools/maxcache/Session.h

Modified: trunk/tools/maxcache/App.cpp
===================================================================
--- trunk/tools/maxcache/App.cpp        2010-05-18 01:36:52 UTC (rev 66598)
+++ trunk/tools/maxcache/App.cpp        2010-05-18 02:38:56 UTC (rev 66599)
@@ -10,7 +10,22 @@
 using namespace MaxCache;
 
 const Time App::NO_TIME( boost::posix_time::not_a_date_time );
+const Time App::INFIN_TIME( boost::posix_time::pos_infin );
 
+App::~App() {
+       SessionList::iterator i;
+       for ( i = mActiveSessions.begin(); i != mActiveSessions.end(); i = 
mActiveSessions.begin() ) {
+               Session & session = *i;
+               mActiveSessions.erase( i );
+               delete &session;
+       }
+       for ( i = mFreeSessions.begin(); i != mFreeSessions.end(); i = 
mFreeSessions.begin() ) {
+               Session & session = *i;
+               mFreeSessions.erase( i );
+               delete &session;
+       }
+}
+
 void App::run( int argc, char** argv ) {
        Endpoint endpoint( Tcp::v4(), 9999 );
        mAcceptor = AcceptorPtr( new Acceptor( mService, endpoint ) );
@@ -22,204 +37,42 @@
        } while ( numHandlers );
 }
 
+Session & App::activateSession() {
+       Session * session;
+       if ( mFreeSessions.empty() ) {
+               session = new Session( *this );
+               mActiveSessions.push_front( *session );
+       } else {
+               SessionList::iterator i = mFreeSessions.begin();
+               mFreeSessions.erase( i );
+               mActiveSessions.push_front( *i );
+               session = &*i;
+       }
+       return *session;
+}
+
+void App::freeSession( Session & session ) {
+       session.reset();
+       mActiveSessions.erase( mActiveSessions.iterator_to( session ) );
+       mFreeSessions.push_front( session );
+}
+
 void App::startAccept() {
-       // Create the peer socket
-       SocketPtr peer( new Socket( mService ) );
+       // Get a session
+       Session & session = activateSession();
+       
        // Start accepting connections
-       mAcceptor->async_accept( *peer, boost::bind( &App::onAccept, this, 
peer, _1 ) );
+       mAcceptor->async_accept( session.getSocket(), 
+                       boost::bind( &App::onAccept, this, boost::ref( session 
), _1 ) );
 }
 
-void App::onAccept( SocketPtr peer, const ErrorCode & acceptError ) {
+void App::onAccept( Session & session, const ErrorCode & acceptError ) {
        if ( acceptError ) {
                throw SystemError( acceptError );
        }
        // Handle this connection
-       startRead( peer );
+       session.startRead();
        // Listen for another connection
        startAccept();
 }
 
-void App::startRead( SocketPtr peer ) {
-       BufferPtr buffer( new Buffer( getMaxCmdLength() ) );
-       Asio::async_read_until( *peer, *buffer, "\r\n",
-               boost::bind( &App::onLineReady, this, peer, buffer, _1, _2 ) );
-}
-
-void App::onLineReady( SocketPtr peer, BufferPtr buffer,
-       const ErrorCode & readError, std::size_t n )
-{
-       if ( readError ) {
-               // Close connection
-               return;
-       }
-
-       std::istream stream( buffer.get() );
-       std::string command;
-
-       // Formatted extraction requires a sensible locale to be set
-       stream.imbue( std::locale( "C" ) );
-
-       stream >> command;
-       if ( handleTooFewParams( peer, stream ) ) return;
-
-       if ( command == "get" ) {
-               std::string key;
-               stream >> key;
-               if ( handleTooFewParams( peer, stream ) ) return;
-
-               CacheEntry * entry = mCache.getEntry( key );
-               if ( !entry ) {
-                       writeMessage( peer, "NO: Item not found\r\n" );
-                       return;
-               }
-
-               writeCacheEntry( peer, entry->getValue() );
-
-       } else if ( command == "set" ) {
-               // Usage: set <key> <expiry> <cost> <value>
-               std::string key;
-               boost::uint32_t expiryInterval, clientCost;
-               StringPtr value( new std::string );
-
-               stream.width( mMaxKeyLength + 1 );
-               stream >> key;
-               if ( handleTooFewParams( peer, stream ) ) return;
-               if ( key.size() > mMaxKeyLength ) {
-                       writeMessage( peer, "ERROR: Key too long\r\n" );
-                       return;
-               }
-
-               stream >> expiryInterval;
-               if ( handleTooFewParams( peer, stream ) ) return;
-               if ( stream.fail() ) {
-                       writeMessage( peer, "ERROR: invalid expiry 
interval\r\n" );
-                       return;
-               }
-
-               // Read the client cost, which is later divided by the size to 
get the 
-               // real cost
-               stream >> clientCost;
-               if ( handleTooFewParams( peer, stream ) ) return;
-               if ( stream.fail() ) {
-                       writeMessage( peer, "ERROR: invalid clientCost\r\n" );
-                       return;
-               }
-
-               stream >> *value;
-               if ( handleTooFewParams( peer, stream ) ) return;
-               if ( value->size() > mCache.getMaxEntrySize() ) {
-                       writeMessage( peer, "ERROR: value too big\r\n" );
-                       return;
-               }
-
-               Time expiry;
-               if ( expiryInterval ) {
-                       expiry = getTime() + boost::posix_time::microseconds( 
expiryInterval );
-               } else {
-                       expiry = Time( boost::posix_time::pos_infin );
-               }
-
-               mCache.setEntry( key, value, clientCost, expiry );
-               writeMessage( peer, "OK: value set\r\n" );
-       } else if ( command == "delete" ) {
-               std::string key;
-               stream.width( mMaxKeyLength + 1 );
-               stream >> key;
-               if ( handleTooFewParams( peer, stream ) ) return;
-               if ( key.size() > mMaxKeyLength ) {
-                       writeMessage( peer, "ERROR: Key too long\r\n" );
-                       return;
-               }
-               
-               if ( mCache.deleteEntry( key ) ) {
-                       writeMessage( peer, "OK: deleted\r\n" );
-               } else {
-                       writeMessage( peer, "NO: not found\r\n" );
-               }
-       } else if ( command == "quit" ) {
-               // Let peer go out of scope and die
-       } else if ( command == "stats" ) {
-               writeStats( peer );
-       } else if ( command == "kill" ) {
-               // TODO: for debugging only, remove this
-               mService.stop();
-       } else {
-               writeMessage( peer, "ERROR: Unknown command\r\n" );
-       }
-}
-
-void App::writeMessage( SocketPtr peer, const char * msg ) {
-       Asio::async_write( 
-               *peer,
-               Asio::const_buffers_1( msg, std::strlen( msg ) ),
-               boost::bind( &App::onWriteMessageDone, this, peer, _1, _2 ) );
-}
-
-void App::onWriteMessageDone( SocketPtr peer, const ErrorCode & writeError, 
std::size_t n ) {
-       if ( writeError ) {
-               // Close connection
-               return;
-       }
-
-       startRead( peer );
-}
-
-void App::writeCacheEntry( SocketPtr peer, StringPtr entry ) {
-       const char prefix[] = "VALUE: ";
-       boost::array<Asio::const_buffer, 3> buffers;
-       buffers[0] = Asio::const_buffer( prefix, sizeof( prefix ) );
-       buffers[1] = Asio::const_buffer( entry->data(), entry->size() );
-       buffers[2] = Asio::const_buffer( "\r\n", 2 );
-
-       Asio::async_write( *peer, buffers,
-               boost::bind( 
-                       &App::onWriteCacheEntryDone, this, peer, 
-                       entry, // just to keep a reference in memory so 
buffers[1] doesn't dangle
-                       _1, _2
-               ) 
-       );
-}
-
-void App::onWriteCacheEntryDone( SocketPtr peer, StringPtr entry, 
-       const ErrorCode & writeError, std::size_t n ) 
-{
-       if ( writeError ) {
-               // Close connection
-               return;
-       }
-       startRead( peer );
-       // entry will go out of scope here and may be deleted
-}
-
-void App::writeStats( SocketPtr peer ) {
-       std::stringstream s;
-       s << "STATS:"
-               << " num-bytes=" << mCache.getNumBytes()
-               << " num-entries=" << mCache.getSize()
-               << " load-factor=" << mCache.getLoadFactor()
-               << " max-bytes=" << mCache.getMaxBytes()
-               << " max-load-factor=" << mCache.getMaxLoadFactor()
-               << "\r\n";
-       StringPtr sp( new std::string( s.str() ) );
-       Asio::async_write(
-               *peer, 
-               Asio::const_buffers_1( sp->data(), sp->size() ),
-               boost::bind( 
-                       &App::onWriteStatsDone, this, peer,
-                       sp, // just to keep a reference to sp
-                       _1, _2
-               )
-       );
-}
-
-void App::onWriteStatsDone( SocketPtr peer, StringPtr buffer,
-       const ErrorCode & writeError, std::size_t n ) 
-{
-       if ( writeError ) {
-               // Close connection
-               return;
-       }
-       startRead( peer );
-       // buffer will go out of scope here and will be deleted
-}
-

Modified: trunk/tools/maxcache/App.h
===================================================================
--- trunk/tools/maxcache/App.h  2010-05-18 01:36:52 UTC (rev 66598)
+++ trunk/tools/maxcache/App.h  2010-05-18 02:38:56 UTC (rev 66599)
@@ -9,22 +9,11 @@
 #include <string>
 #include "typedefs.h"
 #include "Cache.h"
+#include "Session.h"
 
 namespace MaxCache {
 
-namespace Asio = boost::asio;
-typedef boost::asio::ip::tcp Tcp;
-typedef boost::asio::io_service Service;
-typedef Tcp::endpoint Endpoint;
-typedef Tcp::acceptor Acceptor;
-typedef boost::shared_ptr<Acceptor> AcceptorPtr;
-typedef Tcp::socket Socket;
-typedef boost::shared_ptr<Socket> SocketPtr;
-typedef boost::system::error_code ErrorCode;
-typedef boost::system::system_error SystemError;
-typedef boost::asio::streambuf Buffer;
-typedef boost::shared_ptr<Buffer> BufferPtr;
-typedef boost::asio::buffers_iterator< Buffer::const_buffers_type > 
BufferIterator;
+typedef Intrusive::list< Session, SessionListMemberOption > SessionList;
 
 class App {
        public:
@@ -33,8 +22,17 @@
                        mCache( *this, 100000000 )
                {}
 
+               ~App();
+
                void run( int argc, char** argv );
 
+               Session & activateSession();
+               void freeSession( Session & session );
+
+               void stop() {
+                       mService.stop();
+               }
+
                Service & getService() {
                        return mService;
                }
@@ -56,47 +54,31 @@
                        mTime = NO_TIME;
                }
 
+               std::size_t getMaxKeyLength() const { return mMaxKeyLength; }
+
                std::size_t getMaxCmdLength() const {
                        return mCache.getMaxEntrySize() + mMaxKeyLength + 
sizeof( "blah\r\n" );
                }
 
+               const Cache & getCache() const { return mCache; }
+               Cache & getCache() { return mCache; }
+
                void startAccept();
-               void onAccept( SocketPtr peer, const ErrorCode & acceptError );
+               void onAccept( Session & session, const ErrorCode & acceptError 
);
 
-               void startRead( SocketPtr peer );
-               void onLineReady( SocketPtr peer, BufferPtr buffer, 
-                       const ErrorCode & readError, std::size_t n );
-
-               void writeMessage( SocketPtr peer, const char * msg );
-               void onWriteMessageDone( SocketPtr peer, const ErrorCode & 
writeMessage, std::size_t n );
-
-               void writeCacheEntry( SocketPtr peer, StringPtr entry );
-               void onWriteCacheEntryDone( SocketPtr peer, StringPtr entry,
-                       const ErrorCode & writeError, std::size_t n );
-
-               void writeStats( SocketPtr peer );
-               void onWriteStatsDone( SocketPtr peer, StringPtr buffer,
-                               const ErrorCode & writeError, std::size_t n );
+               const static Time NO_TIME;
+               const static Time INFIN_TIME;
        protected:
-               bool handleTooFewParams( SocketPtr peer, std::istream & stream 
) {
-                       if ( stream.eof() ) {
-                               writeMessage( peer, "ERROR: Not enough 
parameters\r\n" );
-                               return true;
-                       } else {
-                               return false;
-                       }
-               }
 
-
                Service mService;
                AcceptorPtr mAcceptor;
+               SessionList mFreeSessions;
+               SessionList mActiveSessions;
 
                const std::size_t mMaxKeyLength;
 
                Cache mCache;
                Time mTime;
-
-               const static Time NO_TIME;
 };
 
 }

Modified: trunk/tools/maxcache/Cache.cpp
===================================================================
--- trunk/tools/maxcache/Cache.cpp      2010-05-18 01:36:52 UTC (rev 66598)
+++ trunk/tools/maxcache/Cache.cpp      2010-05-18 02:38:56 UTC (rev 66599)
@@ -9,6 +9,7 @@
        mBuckets( new KeyTable::bucket_type[mNumBuckets] ),
        mKeyTable( KeyTable::bucket_traits( mBuckets.get(), mNumBuckets ) ),
        mClock( 0 ),
+       mEntryPool( 1024 ),
        mNumBytes( mNumBuckets * sizeof( KeyTable::bucket_type ) ), 
        mMaxBytes( maxBytes ),
        mMaxEntrySizeLog2( 28 ),
@@ -31,7 +32,7 @@
 {
        boost::uint64_t cost = ( (boost::uint64_t)clientCost << 
mMaxEntrySizeLog2 )
                / value->size();
-       CacheEntry * entry = new CacheEntry( *this, key, value, cost, expiry );
+       CacheEntry * entry = newEntry( key, value, cost, expiry );
        setEntryPointer( entry );
 }
 
@@ -45,7 +46,7 @@
                // Too big, ignore this request.
                // This is equivalent to immediate eviction, so it doesn't break
                // the semantics of the insert operation.
-               delete entry;
+               freeEntry( entry );
                return;
        }
 
@@ -93,7 +94,7 @@
        mKeyTable.erase( mKeyTable.iterator_to( entry ) );
        mCostTree.erase( mCostTree.iterator_to( entry ) );
        mExpiryTree.erase( mExpiryTree.iterator_to( entry ) );
-       delete &entry;
+       freeEntry( &entry );
 }
 
 void Cache::evictUntilNormalSize() {

Modified: trunk/tools/maxcache/Cache.h
===================================================================
--- trunk/tools/maxcache/Cache.h        2010-05-18 01:36:52 UTC (rev 66598)
+++ trunk/tools/maxcache/Cache.h        2010-05-18 02:38:56 UTC (rev 66599)
@@ -4,6 +4,7 @@
 #include "boost-config.h"
 #include "CacheEntry.h"
 #include <boost/shared_array.hpp>
+#include <boost/pool/object_pool.hpp>
 
 namespace MaxCache {
 
@@ -27,6 +28,8 @@
        compare< CacheEntry::CompareExpiries >
        > ExpiryTree;
 
+typedef boost::object_pool<CacheEntry> CacheEntryPool;
+
 class App;
 
 class Cache {
@@ -119,6 +122,27 @@
                 */
                void evictExpiredEntries();
 
+               /**
+                * Create a new CacheEntry object
+                */
+               CacheEntry * newEntry( const std::string & key, StringPtr 
value, 
+                       boost::uint64_t cost, Time expiry ) 
+               {
+                       CacheEntry * entry = mEntryPool.malloc();
+                       mEntryPool.set_next_size( 1024 );
+                       new ( entry ) CacheEntry( *this, key, value, cost, 
expiry );
+                       return entry;
+                       //return new CacheEntry( *this, key, value, cost, 
expiry );
+               }
+
+               /**
+                * Free a CacheEntry object created by newEntry()
+                */
+               void freeEntry( CacheEntry * entry ) {
+                       mEntryPool.free( entry );
+                       //delete entry;
+               }
+
                float mMaxLoadFactor;
                std::size_t mNumBuckets;
                boost::shared_array<KeyTable::bucket_type> mBuckets;
@@ -128,6 +152,8 @@
                ExpiryTree mExpiryTree;
                boost::uint64_t mClock;
 
+               CacheEntryPool mEntryPool;
+
                std::size_t mNumBytes;
                std::size_t mMaxBytes;
                unsigned char mMaxEntrySizeLog2;

Modified: trunk/tools/maxcache/CacheEntry.h
===================================================================
--- trunk/tools/maxcache/CacheEntry.h   2010-05-18 01:36:52 UTC (rev 66598)
+++ trunk/tools/maxcache/CacheEntry.h   2010-05-18 02:38:56 UTC (rev 66599)
@@ -14,10 +14,8 @@
 
 namespace MaxCache {
 
-namespace Intrusive = boost::intrusive;
-
 typedef Intrusive::unordered_set_member_hook< store_hash<true> > HashHook;
-typedef Intrusive::set_base_hook<> TreeHook;
+typedef Intrusive::set_member_hook<> TreeHook;
 
 class Cache;
 

Modified: trunk/tools/maxcache/Makefile
===================================================================
--- trunk/tools/maxcache/Makefile       2010-05-18 01:36:52 UTC (rev 66598)
+++ trunk/tools/maxcache/Makefile       2010-05-18 02:38:56 UTC (rev 66599)
@@ -2,7 +2,7 @@
 
 CFLAGS:=$(CFLAGS) -ggdb3 -Wall
 
-maxcache: maxcache.o App.o CacheEntry.o Cache.o
+maxcache: maxcache.o App.o CacheEntry.o Cache.o Session.o
        g++ $^ $(CFLAGS) -lboost_system -o $@
 
 %.o : %.cpp

Added: trunk/tools/maxcache/Session.cpp
===================================================================
--- trunk/tools/maxcache/Session.cpp                            (rev 0)
+++ trunk/tools/maxcache/Session.cpp    2010-05-18 02:38:56 UTC (rev 66599)
@@ -0,0 +1,216 @@
+#include "Session.h"
+#include "App.h"
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+using namespace MaxCache;
+
+Session::Session( App & app )
+       : mApp( app ),
+       mSocket( app.getService() ),
+       mInputBuffer( app.getMaxCmdLength() )
+{}
+
+void Session::reset()
+{
+       if ( mSocket.is_open() ) {
+               mSocket.shutdown( Socket::shutdown_both );
+               mSocket.close();
+       }
+       if ( mInputBuffer.size() ) {
+               mInputBuffer.consume( mInputBuffer.size() );
+       }
+       mWriteBuffer.clear();
+}
+
+void Session::startRead()
+{
+       Asio::async_read_until( mSocket, mInputBuffer, "\r\n",
+               boost::bind( &Session::onLineReady, this, _1, _2 ) );
+}
+
+void Session::onLineReady( const ErrorCode & readError, std::size_t n )
+{
+       if ( readError ) {
+               // Close connection
+               mApp.freeSession( *this );
+               return;
+       }
+       
+       std::string line;
+       line.reserve( n );
+       BOOST_FOREACH( Asio::const_buffer block, mInputBuffer.data() ) {
+               line.append( Asio::buffer_cast<const char*>( block ), 
Asio::buffer_size( block ) );
+       }
+       mInputBuffer.consume( n );
+       std::stringstream stream( line );
+
+       // Formatted extraction requires a sensible locale to be set
+       stream.imbue( std::locale( "C" ) );
+
+       std::string command;
+       stream >> command;
+       if ( handleTooFewParams( stream ) ) return;
+
+       if ( command == "get" ) {
+               std::string key;
+               stream >> key;
+               if ( handleTooFewParams( stream ) ) return;
+
+               CacheEntry * entry = mApp.getCache().getEntry( key );
+               if ( !entry ) {
+                       writeMessage( "NO: Item not found\r\n" );
+                       return;
+               }
+
+               writeCacheEntry( entry->getValue() );
+
+       } else if ( command == "set" ) {
+               // Usage: set <key> <expiry> <cost> <value>
+               std::string key;
+               boost::uint32_t expiryInterval, clientCost;
+               StringPtr value( new std::string );
+
+               stream.width( mApp.getMaxKeyLength() + 1 );
+               stream >> key;
+               if ( handleTooFewParams( stream ) ) return;
+               if ( key.size() > mApp.getMaxKeyLength() ) {
+                       writeMessage( "ERROR: Key too long\r\n" );
+                       return;
+               }
+
+               stream >> expiryInterval;
+               if ( handleTooFewParams( stream ) ) return;
+               if ( stream.fail() ) {
+                       writeMessage( "ERROR: invalid expiry interval\r\n" );
+                       return;
+               }
+
+               // Read the client cost, which is later divided by the size to 
get the 
+               // real cost
+               stream >> clientCost;
+               if ( handleTooFewParams( stream ) ) return;
+               if ( stream.fail() ) {
+                       writeMessage( "ERROR: invalid clientCost\r\n" );
+                       return;
+               }
+
+               stream >> *value;
+               if ( handleTooFewParams( stream ) ) return;
+               if ( value->size() > mApp.getCache().getMaxEntrySize() ) {
+                       // This won't happen very often, usually the ASIO 
buffer limit will 
+                       // be exceeded instead.
+                       writeMessage( "ERROR: value too big\r\n" );
+                       return;
+               }
+
+               Time expiry;
+               if ( expiryInterval ) {
+                       expiry = mApp.getTime() + 
boost::posix_time::microseconds( expiryInterval );
+               } else {
+                       expiry = Time( App::INFIN_TIME );
+               }
+
+               mApp.getCache().setEntry( key, value, clientCost, expiry );
+               writeMessage( "OK: value set\r\n" );
+       } else if ( command == "delete" ) {
+               std::string key;
+               stream.width( mApp.getMaxKeyLength() + 1 );
+               stream >> key;
+               if ( handleTooFewParams( stream ) ) return;
+               if ( key.size() > mApp.getMaxKeyLength() ) {
+                       writeMessage( "ERROR: Key too long\r\n" );
+                       return;
+               }
+               
+               if ( mApp.getCache().deleteEntry( key ) ) {
+                       writeMessage( "OK: deleted\r\n" );
+               } else {
+                       writeMessage( "NO: not found\r\n" );
+               }
+       } else if ( command == "quit" ) {
+               mApp.freeSession( *this );
+       } else if ( command == "stats" ) {
+               writeStats();
+       } else if ( command == "kill" ) {
+               // TODO: for debugging only, remove this
+               mApp.stop();
+       } else {
+               writeMessage( "ERROR: Unknown command\r\n" );
+       }
+}
+
+void Session::writeMessage( const char * msg ) {
+       Asio::async_write( 
+               mSocket,
+               Asio::const_buffers_1( msg, std::strlen( msg ) ),
+               boost::bind( &Session::onWriteMessageDone, this, _1, _2 ) );
+}
+
+void Session::onWriteMessageDone( const ErrorCode & writeError, std::size_t n 
) {
+       if ( writeError ) {
+               // Close connection
+               mApp.freeSession( *this );
+               return;
+       }
+
+       startRead();
+}
+
+void Session::writeCacheEntry( StringPtr entry ) {
+       const char prefix[] = "VALUE: ";
+
+       boost::array<Asio::const_buffer, 3> buffers;
+       buffers[0] = Asio::const_buffer( prefix, sizeof( prefix ) );
+       buffers[1] = Asio::const_buffer( entry->data(), entry->size() );
+       buffers[2] = Asio::const_buffer( "\r\n", 2 );
+
+       Asio::async_write( mSocket, buffers,
+               boost::bind(
+                       &Session::onWriteCacheEntryDone, this, 
+                       entry, // just to keep a reference in memory so 
buffers[1] doesn't dangle
+                       _1, _2
+               ) 
+       );
+}
+
+void Session::onWriteCacheEntryDone( StringPtr entry, const ErrorCode & 
writeError, 
+               std::size_t n ) 
+{
+       if ( writeError ) {
+               // Close connection
+               mApp.freeSession( *this );
+               return;
+       }
+       startRead();
+       // entry will go out of scope here and may be deleted
+}
+
+void Session::writeStats() {
+       std::stringstream s;
+       s << "STATS:"
+               << " num-bytes=" << mApp.getCache().getNumBytes()
+               << " num-entries=" << mApp.getCache().getSize()
+               << " load-factor=" << mApp.getCache().getLoadFactor()
+               << " max-bytes=" << mApp.getCache().getMaxBytes()
+               << " max-load-factor=" << mApp.getCache().getMaxLoadFactor()
+               << "\r\n";
+       mWriteBuffer = s.str();
+       Asio::async_write(
+               mSocket, 
+               Asio::const_buffers_1( mWriteBuffer.data(), mWriteBuffer.size() 
),
+               boost::bind( &Session::onWriteStatsDone, this, _1, _2 ) 
+       );
+}
+
+void Session::onWriteStatsDone( const ErrorCode & writeError, std::size_t n ) 
+{
+       if ( writeError ) {
+               // Close connection
+               mApp.freeSession( *this );
+               return;
+       }
+       startRead();
+       // buffer will go out of scope here and will be deleted
+}
+


Property changes on: trunk/tools/maxcache/Session.cpp
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/tools/maxcache/Session.h
===================================================================
--- trunk/tools/maxcache/Session.h                              (rev 0)
+++ trunk/tools/maxcache/Session.h      2010-05-18 02:38:56 UTC (rev 66599)
@@ -0,0 +1,58 @@
+#ifndef MAXCACHE_SESSION_H
+#define MAXCACHE_SESSION_H
+
+#include "boost-config.h"
+#include <boost/intrusive/list.hpp>
+#include "typedefs.h"
+
+using namespace boost::intrusive;
+
+namespace MaxCache {
+
+typedef Intrusive::list_member_hook<> ListHook;
+
+class App;
+
+class Session {
+       public:
+               Session( App & app );
+               void reset();
+
+               Socket & getSocket() {
+                       return mSocket;
+               }
+
+               void startRead();
+               void onLineReady( const ErrorCode & readError, std::size_t n );
+
+               void writeMessage( const char * msg );
+               void onWriteMessageDone( const ErrorCode & writeError, 
std::size_t n );
+
+               void writeCacheEntry( StringPtr entry );
+               void onWriteCacheEntryDone( StringPtr entry, const ErrorCode & 
writeError, std::size_t n );
+
+               void writeStats();
+               void onWriteStatsDone( const ErrorCode & writeError, 
std::size_t n );
+
+               ListHook mListHook;
+
+       protected:
+               bool handleTooFewParams( std::istream & stream ) {
+                       if ( stream.eof() ) {
+                               writeMessage( "ERROR: Not enough 
parameters\r\n" );
+                               return true;
+                       } else {
+                               return false;
+                       }
+               }
+
+               App & mApp;
+               Socket mSocket;
+               Buffer mInputBuffer;
+               std::string mWriteBuffer;
+};
+
+typedef Intrusive::member_hook< Session, ListHook, &Session::mListHook > 
SessionListMemberOption;
+
+}
+#endif


Property changes on: trunk/tools/maxcache/Session.h
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: trunk/tools/maxcache/typedefs.h
===================================================================
--- trunk/tools/maxcache/typedefs.h     2010-05-18 01:36:52 UTC (rev 66598)
+++ trunk/tools/maxcache/typedefs.h     2010-05-18 02:38:56 UTC (rev 66599)
@@ -1,12 +1,36 @@
 #ifndef MAXCACHE_TYPEDEFS_H
 #define MAXCACHE_TYPEDEFS_H
 
+#include "boost-config.h"
 #include <string>
 #include <boost/shared_ptr.hpp>
 #include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/intrusive/intrusive_fwd.hpp>
+#include <boost/asio.hpp>
+
 namespace MaxCache {
+       // Misc
        typedef boost::shared_ptr<std::string> StringPtr;
        typedef boost::posix_time::ptime Time;
+
+       // Intrusive
+       namespace Intrusive = boost::intrusive;
+
+       // Asio
+       namespace Asio = boost::asio;
+
+       typedef Asio::ip::tcp Tcp;
+       typedef Asio::io_service Service;
+       typedef Tcp::endpoint Endpoint;
+       typedef Tcp::acceptor Acceptor;
+       typedef boost::shared_ptr<Acceptor> AcceptorPtr;
+       typedef boost::system::error_code ErrorCode;
+       typedef boost::system::system_error SystemError;
+
+       typedef Asio::streambuf Buffer;
+       typedef Asio::buffers_iterator< Buffer::const_buffers_type > 
BufferIterator;
+       typedef Tcp::socket Socket;
+       
 }
 
 #endif



_______________________________________________
MediaWiki-CVS mailing list
MediaWiki-CVS@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to