CMS 3D CMS Logo

IgServerPool.cc

Go to the documentation of this file.
00001 //<<<<<< INCLUDES                                                       >>>>>>
00002 
00003 #include "Iguana/WebFramework/interface/IgServerPool.h"
00004 #include "Iguana/WebFramework/interface/IgServerSocket.h"
00005 #include "Iguana/Framework/interface/IgArgsElement.h"
00006 #include "Iguana/Framework/interface/IgState.h"
00007 #include <classlib/iobase/SubProcess.h>
00008 #include <classlib/iobase/TempFile.h>
00009 #include <classlib/utils/DebugAids.h>
00010 #include <classlib/utils/StringOps.h>
00011 #include <classlib/utils/StringList.h>
00012 #include <classlib/iobase/Filename.h>
00013 #include <classlib/utils/Argz.h>
00014 #include <stdlib.h>
00015 #include <iostream>
00016 #include <signal.h>
00017 #include <sys/wait.h>
00018 
00019 //<<<<<< PRIVATE DEFINES                                                >>>>>>
00020 //<<<<<< PRIVATE CONSTANTS                                              >>>>>>
00021 //<<<<<< PRIVATE TYPES                                                  >>>>>>
00022 //<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
00023 //<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
00024 
00025 IgServerPool* IgServerPool::m_instance = 0;
00026 
00027 //<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
00028 
00029 IG_DEFINE_STATE_ELEMENT (IgServerPool, "Server pool");
00030 
00031 //<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
00032 
00033 void childServerFinished (int signum)
00034 {
00035     if (signum != SIGCHLD) return;
00036     int status;
00037     IgServerPool::getInstance(0)->childTerminated(wait (&status));
00038 }
00039 //<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
00040 //<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
00041 IgServerPool* IgServerPool::getInstance (IgState *state)
00042 {
00043     if (!m_instance)
00044         m_instance = new IgServerPool(state);
00045     return m_instance;
00046 }
00047 
00048 IgServerPool::IgServerPool (IgState *state)
00049     : m_state (state), 
00050       m_argz (new lat::Argz ("iguana")),
00051       m_maxProcesses (65000),
00052       m_processPoolSize(2),
00053       m_hostname ("")
00054 {
00055     m_state->put (s_key, this);
00056     signal (SIGCHLD, childServerFinished);
00057     
00058     IgArgsElement *args = IgArgsElement::get (state);
00059     std::string processPoolSize = QString::number(m_processPoolSize);
00060     if (args->find ("--ig-process-pool-size", processPoolSize))
00061         m_processPoolSize = atoi (processPoolSize.c_str ());
00062 
00063     std::string maxProcesses = QString::number(m_maxProcesses);
00064     if (args->find ("--ig-max-processes", maxProcesses))
00065         m_maxProcesses = atoi (maxProcesses.c_str ());
00066         
00067     ASSERT (m_processPoolSize <= m_maxProcesses);
00068 
00069     m_hostname = IgServerSocket::cmdLineHostname(m_state);
00070     ASSERT (!m_hostname.empty());
00071 
00072     m_argz->add ("-D");
00073     m_argz->add ("SOCKET");
00074     
00075     if (IgServerSocket::cmdLineProxy(state).empty())
00076     {
00077         m_argz->add ("--ig-main-hosturl");
00078         m_argz->add (m_hostname + ":" +
00079                      QString::number(IgServerSocket::cmdLinePort(state)));
00080     }
00081     // copy the arguments from command-line
00082     // map of "<command-line arg>=<has value?>" which should not be passed to
00083     // child server.
00084     std::map <std::string, bool> ignoreArgs;
00085     ignoreArgs ["--ig-port"]=true;
00086     ignoreArgs ["--ig-server"]=false;
00087     ignoreArgs ["--ig-main-hosturl"]=true;
00088     ignoreArgs ["--ig-process-pool-size"]=true;
00089     ignoreArgs ["--ig-max-processes"]=true;
00090     ignoreArgs ["-D"]=true;
00091     ignoreArgs ["--driver"]=true;
00092         
00093     for (int i = 1 ; i < args->args (); i++)
00094     {
00095         std::string arg (args->arg (i));
00096         if (arg.empty ()) continue;
00097         if (ignoreArgs.find (arg) != ignoreArgs.end())
00098         {
00099             if (ignoreArgs[arg])
00100                 i++;
00101         }
00102         else
00103             m_argz->add (args->arg (i));
00104     }
00105 
00106     for (int i = 0; i < m_processPoolSize; i++)
00107         addServer ();
00108 }
00109 
00110 IgServerPool::~IgServerPool (void)
00111 {
00112     m_state->detach (s_key);    
00113 }
00114 
00115 
00116 std::string
00117 IgServerPool::createProcess (void)
00118 {
00119     lat::Argz argz (*m_argz);
00120     int childPort = IgServerSocket::getFreePort ();
00121     std::string portValue = QString::number (childPort).latin1 ();    
00122     argz.add ("--ig-port");
00123     argz.add (portValue);
00124     lat::SubProcess *process = new lat::SubProcess ();
00125     
00126     std::cerr << argz.quote () << std::endl;
00127     
00128     lat::Argz shellCommand ("/bin/sh");
00129     shellCommand.add ("-c");
00130     lat::Filename directoryName (lat::TempFile::tempdir().asDirectory());
00131     directoryName.append ("IGUANAWEB/");
00132     directoryName.makedir(directoryName, 0700, true, true);
00133     lat::TempFile::dir (directoryName);
00134     
00135     shellCommand.add (std::string ("\"cd ") + directoryName.name () + "; "+
00136                       argz.quote () + "\"");
00137     std::cerr << shellCommand.quote () << std::endl;
00138     
00139     pid_t pid = process->run (shellCommand.argz ());
00140     
00141     std::string result = m_hostname + ":" + portValue;    
00142     m_pidServerMap.insert (std::pair<pid_t, std::string>(pid,result));
00143     
00144     return result;
00145 }
00146 
00147 std::string
00148 IgServerPool::redirect (const std::string& url, std::string& cookie)
00149 {
00150     std::string result;
00151     std::string redir;
00152 
00153     if (cookie.empty())
00154       IgServerSocket::generateCookie (cookie);
00155       
00156     if (m_cookieServerMap.find (cookie) != m_cookieServerMap.end ())
00157     {
00158         redir = m_cookieServerMap[cookie];
00159     }
00160     else 
00161     {
00162         if (m_availableServers.size ())
00163         {
00164             // We have atleast one child server available
00165             redir = *(m_availableServers.begin ());
00166             m_availableServers.erase (m_availableServers.begin ());
00167             m_cookieServerMap.insert (std::pair<std::string, std::string>
00168                                       (cookie,redir));
00169         }
00170         else
00171         {
00172             // Already serving max number of clients.
00173             result = "HTTP/1.1 200 Ok\r\n"
00174                      "Content-Type: text/html; charset=\"utf-8\"\r\n\r\n"
00175                      "<html><body>"          
00176                      "<style  type=\"text/css\">"
00177                      "a {color:#FFFFFF}"
00178                      "</style>"
00179                      "<h3>Server is busy.</h3>"
00180                      "Max number of clients are already connected. Please try again later."
00181                      "</body>"
00182                      "</html>\r\n\r\n";
00183     
00184             std::cerr << result << std::endl;
00185     
00186             return result;    
00187         }
00188     }  
00189     
00190     return IgServerSocket::redirect (url, redir, cookie);
00191 }
00192 
00193 void
00194 IgServerPool::addServer (void)
00195 {
00196     if (((int)m_pidServerMap.size() < m_maxProcesses) &&
00197         ((int)m_availableServers.size () < m_processPoolSize))
00198     {
00199         m_availableServers.insert (createProcess ());
00200     }
00201 }
00202 
00203 
00204 void
00205 IgServerPool::childTerminated (int pid)
00206 {
00207     PIDToServerMap::iterator pidItr = m_pidServerMap.find(pid);
00208     if (pidItr != m_pidServerMap.end())
00209     {
00210         std::string server = m_pidServerMap[pid];
00211         std::cerr <<"Server terminated:"<<server<<std::endl;
00212         m_pidServerMap.erase(pidItr);
00213         if (m_availableServers.find(server)!=m_availableServers.end())
00214             m_availableServers.erase (server);
00215         CookieToServerMap::iterator itr = m_cookieServerMap.begin();
00216         for(itr = m_cookieServerMap.begin();
00217             itr != m_cookieServerMap.end();
00218             itr++)
00219         {
00220             if (itr->second == server)
00221                 m_cookieServerMap.erase (itr);
00222         }
00223         addServer ();
00224     }
00225 }
00226 
00227 int 
00228 IgServerPool::availableServers (void)const
00229 {
00230     return m_availableServers.size ();    
00231 }
00232 
00233 int
00234 IgServerPool::processPoolSize (void) const
00235 { return m_processPoolSize; }

Generated on Tue Jun 9 17:39:03 2009 for CMSSW by  doxygen 1.5.4