CppCMS Blog :: Framework http://blog.cppcms.com/ A blog on CppCMS - C++ Web Development Framework Serving All Israeli News Web Sites from a Single EC2 instance... http://blog.cppcms.com/post/114 http://blog.cppcms.com/post/114 <div style="direction:ltr"> <p>For the last year the development of the CppCMS project was less active. The vast majority of the work hours were spent on a customer's project that used CppCMS to create an outstanding advertisement system.</p> <p>The project is called <a href="http://linicom.co.il">Linicom</a>.</p> <p>Today, when Linicom is up, running and maintained by a larger team, so I can resume the activity on the core CppCMS project itself.</p> <p>Few words about Linicom:</p> <p>Linicom is an engine that provides content and visitor sensitive advertisements for almost all large Israeli news web sites: including Ynet, Haaretz, Jerusalem Post, Mako, Walla and other significant web sites in Israel and abroad.</p> <p>Here some interesting facts:</p> <ul> <li>Linicom is based on CppCMS technology.</li> <li>The system serves around 10,000,000 <em>custom</em> requests a day, i.e ~115 req./s.</li> <li>During peak hours, it servers around 160 requests per second.</li> <li>Its typical network output is around 11 megabit per second.</li> <li>Its total memory consumption (web server, database, applications, OS) is only around 350Mb.</li> <li>The server's average CPU load is around 5%</li> <li>The server runs on a <code>c1.medium</code> Amazon EC2 instance.</li> </ul> <p>The system runs behind Lighttpd and uses PostgreSQL for persistent data storage. Also PostgreSQL is used extensively, all real time data is stored in memory.</p> <p>Almost every request needs data processing in order to provide highly customized advertisements. In technical terms it means that almost no request can be "outsourced" to a static files - every request for every customer should be processed explicitly.</p> <p>This system is probably one of the classic applications of CppCMS technology - web based system that required to be fast and efficient, being able to handle outstanding and sometimes unexpectedly changing loads without problems and provide high QoS.</p> <p>Use of in-memory data storage, caching and efficient handing of the data that can't be cached is were CppCMS shines. Having a big growth potential with a minimal required maintenance and high reliability allows the to handle the business-end safely without worrying about performance issues.</p> </div> CppCMS Project Receives Donations... http://blog.cppcms.com/post/96 http://blog.cppcms.com/post/96 <div style="direction:ltr"> <p><span style="float:right; padding-left:20px"><a href="http://sourceforge.net/donate/index.php?group_id=209965"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a></span> CppCMS project receives monetary donations using sourceforge donation system.</p> <p>If you are using this project consider donating some money. Follow the donations button on the CppCMS projects <a href="http://cppcms.sourceforge.net/wikipp/en/page/main">web site</a> or the button in this post.</p> <p>The money would help to create a better product and provide better service to the CppCMS users community.</p> </div> CppCMS 0.999.0 - Release Candidate 1 http://blog.cppcms.com/post/94 http://blog.cppcms.com/post/94 <div style="direction:ltr"> <p>The first release candidate of the next version of CppCMS is available - the API can be considered stable from this point and would not be changed in backward incompatible way.</p> <p><em>New Features:</em></p> <ul> <li><p>Templates engine improvements:</p> <ul> <li><p>Added template helpers support functions <a href="http://art-blog.no-ip.info/wikipp/en/page/cppcms_1x_templates_comm#Views.Helpers"><code>&lt;% using ... %&gt;</code></a> and <a href="http://art-blog.no-ip.info/wikipp/en/page/cppcms_1x_templates_comm#Rendering.other.views"><code>&lt;% render ... %&gt;</code></a> that allow using other views directly from the code and not just templates as it was done before.</p></li> <li><p>Added new syntax</p> <pre><code>&lt;% form block foo %&gt;...&lt;% end %&gt; </code></pre> <p>as better alternative to:</p> <pre><code>&lt;% form begin foo %&gt;...&lt;% form end foo %&gt; </code></pre></li> <li><p>Improved error messages in templates compiler such that it gives more clear errors in case of syntax error.</p></li> <li><p>Changed semantics of <code>application::render</code> function such that it would not override an application that was assigned to the contend (if it was assigned at all)</p></li> </ul> </li> <li><p><code>cppcms_scale</code> improvements:</p> <ul> <li>Support of session storage in addition to cache storage now providing full scalability of CppCMS services.</li> <li>Now it uses same configuration method as CppCMS process - JSON file with optional command line parameters.</li> <li><code>cppcms_scale</code> now can run as Unix deamon and as Windows service.</li> </ul> </li> <li><p>URL Mapper does not throws by default, but rather create an invalid URL making initial programming easier.</p> <p>The behavior can be reverted back by setting <code>misk.invalid_url_throws</code> option to true.</p></li> <li><p>Added recursive <code>shared_mutex</code> support to booster.</p></li> <li><p>Provided an experimental support of STLPort 5.2.</p></li> </ul> </div> CppCMS Nightly Tests http://blog.cppcms.com/post/68 http://blog.cppcms.com/post/68 <div style="direction:ltr"> <p>Hello All,</p> <p>In order to simplify CppCMS release procedure and ensure that current SVN trunk it not got broken on platforms that are used less frequently the night build and test were set up.</p> <p>Each night svn-trunk is <a href="http://art-blog.no-ip.info/files/nightly-build-report.html">tested with different compilers and platforms</a>. The full test matrix in not complete yet, but most important platforms and compilers are tested (or actually the plafroms that can be tested relatievly easily)</p> <p>It is expected to be extedned more in future.</p> <p>Thanks to <a href="http://www.virtualbox.org/">VirtualBox</a> for simple and convinient virtualization solutions.</p> </div> First beta version of CppCMS 1.x.x is officially out! http://blog.cppcms.com/post/63 http://blog.cppcms.com/post/63 <div style="direction:ltr"> <p>Hello all CppCMS users.</p> <p>The first beta version of CppCMS 1.x.x is available for download from the <a href="https://sourceforge.net/projects/cppcms/files/">Sourceforge</a>. The build instructions can be found <a href="http://cppcms.sourceforge.net/wikipp/en/page/cppcms_1x_build">here</a>.</p> <p>This version very different from CppCMS 0.0.x branch - it fixes many design flaws that had been done the previous version, it is almost 90% rewrite of the original code according to new design.</p> <p>It also includes many <a href="http://cppcms.sourceforge.net/wikipp/en/page/cppcms_1x_whats_new">important features</a></p> <p>Most significant ones:</p> <ul> <li><p>Full CppCMS core rewrite that introduced:</p> <ul> <li>Asynchronous programming support</li> <li>Removal of 3rd part libraries from the core api.</li> <li>Stable API and ABI through all major releases.</li> </ul> </li> <li>Improved Ajax support with introduction of JSON-RPC</li> <li>Powerful i18n and l10n</li> <li>Native Windows support including support of MSVC.</li> <li>And much more...</li> </ul> <p>So now CppCMS beta is ready.</p> <p>Hopefully first release candidate version will be ready withing about a 3 month. And the first stable release is expected at the end of 2010 beginning of 2011.</p> </div> Wikipp is converted to new CppCMS 1.x.x and running on main site! http://blog.cppcms.com/post/59 http://blog.cppcms.com/post/59 <div style="direction:ltr"> <p>Hello all,</p> <p><a href="http://art-blog.no-ip.info/wikipp/en/page/main">Wikipp</a> is now running on top of alpha version of CppCMS 1.x.x. It is one important step to release of first beta version of new generation of CppCMS.</p> <p>Update me if you have any issues.</p> </div> CppCMS 1.x.x updates http://blog.cppcms.com/post/58 http://blog.cppcms.com/post/58 <div style="direction:ltr"> <p>After big internal changes I explain some critical architectural updates that CppCMS 1.x.x did.</p> <p>In few words:</p> <ol> <li>Removed <code>cppcms_boost</code> library. Only several essential tools, not visible to API are still taken from <code>cppcms_boost</code> which compiled statically into cppcms library.</li> <li>Booster library was introduced. It is a library with boost-like interfaces that do not depend on actual boost. Some of the code is taken from boost library, some are wrappers of good C libraries and some totally new code I had written with ABI compatibility in mind.</li> </ol> <p>Following my <a href="http://art-blog.no-ip.info/cppcms/blog/post/57">previous post</a> feel free to update your working copies.</p> <h2>Rationale</h2> <p>CppCMS 1.x.x would provide backward compatible API and ABI and thus it can't relate on Boost library in it's public API. Only possible way to provide Boost API to users is actually wrapping it.</p> <p>CppCMS 1.x.x introduces asynchronous even loop to web development - something that is very critical for Comet programming. This loop was based on Boost.Asio. But unfortunately it had very big limitations and writing a good wrapper Boost.Asio was unfeasible.</p> <p>So a small "Boost_er_" library replaced required functionality from boost partially reimplementing, partially wrapping C libraries and partially borrowing the code from Boost itself.</p> <p>Booster has following components:</p> <ul> <li>Smart pointers: <code>shared_ptr</code>, <code>intrusive_ptr</code> from Boost and small pointers for pimpl design: <code>hold_ptr</code>, <code>copy_ptr</code> and <code>clone_ptr</code> (my own).</li> <li>Function - similar to <code>std::tr1::function</code> and <code>boost::function</code> - small class important for callbacks implementation (my own implementation).</li> <li>Regular expressions - wrapper of PCRE library with Boost.Regex like API. It provides only <code>regex</code>, <code>match_result</code>, <code>regex_search</code> and <code>regex_match</code>.</li> <li>System: <code>error_code</code>, <code>error_category</code> and <code>system_error</code> (my own).</li> <li>Thread: Boost like pthreads wrapper.</li> <li>Locale - full Boost.Locale library (my own).</li> <li>And the most important AIO library - library inspired by Asio.</li> </ul> <p>The AIO library it is central CppCMS event loop that has Asio like API - proactor design, callback interface, etc.</p> <p>However unlike ASIO it uses very few template classes, it is prefork-friendly (<a href="https://svn.boost.org/trac/boost/ticket/4162">unlike ASIO</a>)</p> <p>Booster.Aio interface would allow Comet application to receive various asynchronous notifications from any source that can deliver such notifications over sockets.</p> </div> CppCMS 0.0.5 (Stable) Released http://blog.cppcms.com/post/53 http://blog.cppcms.com/post/53 <div style="direction:ltr"> <p>Hello All,</p> <p>Version 0.0.5 of CppCMS framework (stable brunch) had been released. So far:</p> <h3>Security Bugs:</h3> <ul> <li>Workaround of CgiCC bug that may cause process shutdown in case of huge POST requests - DoS.</li> <li>Fixed generation of session ids that could create session ids with very low entropy -- guessable SID.</li> </ul> <h3>Bugs:</h3> <ul> <li>Fixed: incorrect update of "exposed" session values, when renewing session life time.</li> <li>Fixed: bug that prevent using FastCGI/SCGI over TCP.</li> <li>Fixed: build fault when using <code>--boost-suffix</code> configure option</li> <li>Fixed: incorrect generation of status headers in case of errors.</li> <li>Fixed: build issues with <code>gcc-4.4.1</code></li> <li>Fixed: various issues with for Intel Compiler support.</li> </ul> <h3>Improvements:</h3> <ul> <li>Removed all unnecessary classes from views -- compilation time speedup up to 3.2 times (of views)</li> </ul> </div> CppCMS 1.x.x moves to CMake http://blog.cppcms.com/post/51 http://blog.cppcms.com/post/51 <div style="direction:ltr"> <p>No, I don't think that CMake is better then autotools. In fact I still think that CMake is total "crap". It has terrible cache policy, it has broken <code>configuration_file</code> support. It is crappy documentation and many broken configuration tools like CheckTypeSizeOf... and much more.</p> <p>But it supports MSVC (that I may think supporting in future) and has a better Windows support... So I announce that next version of CppCMS would use CMake (and it already uses in re-factoring branch).</p> <p>Autotools build system is no longer supported and will be removed from the CppCMS 1.x.x branch, because I do not really like supporting two build systems.</p> <p>I hope CppCMS users would understand this terrible move.</p> </div> CppCMS meets Comet http://blog.cppcms.com/post/47 http://blog.cppcms.com/post/47 <div style="direction:ltr"> <p>One of the major requirements for framework refactoring was support of <a href="http://en.wikipedia.org/wiki/Comet_(programming)">Comet</a>. Now, with introduction of asynchronous request handling and persistent application servers it becomes reality.</p> <h3>Client Side</h3> <p>There is a HTML <a href="http://cppcms.svn.sourceforge.net/viewvc/cppcms/framework/trunk/examples/chat/the_chat.html?revision=2000&amp;view=markup">source</a> of simple chat client, that uses <a href="http://www.dojotoolkit.org/">Dojo</a> toolkit. It does following:</p> <ol> <li><p>Submits new messages to the server application by posting form using XHR:</p> <pre><code> function send_data() { var kw = { url : "/chat/post", form : "theform" }; dojo.xhrPost(kw); dojo.byId("message").value=""; return false; } </code></pre></li> <li><p>Receives new messages from the server using long poll via XHR:</p> <pre><code> var message_count = 0; function read_data() { dojo.xhrGet( { url: "/chat/get/" + message_count, timeout: 120000, handleAs: "text", load: function(response, ioArgs) { dojo.byId("messages").innerHTML = response + '&lt;br/&gt;' + dojo.byId("messages").innerHTML; message_count++; read_data(); return response; }, error: function(response,ioArgs) { read_data(); return response; } }); } dojo.addOnLoad(read_data); </code></pre></li> </ol> <p>So, the client side is quite simple (however error handling should be quite better).</p> <h3>Server Side</h3> <p>First we create our long running asynchronous application, that receives two kinds for requests: "/post" -- with new data, and "/get/NN" -- receive message nuber NN, we assign these calls to two member functions <code>post</code> and <code>get</code>.</p> <pre><code>class chat : public cppcms::application { public: chat(cppcms::service &amp;srv) : cppcms::application(srv) { dispatcher().assign("^/post$",&amp;chat::post,this); dispatcher().assign("^/get/(\\d+)$",&amp;chat::get,this,1); } </code></pre> <p>Now, this class includes two data members:</p> <pre><code>private: std::vector&lt;std::string&gt; messages_; std::vector&lt;cppcms::intrusive_ptr&lt;cppcms::http::context&gt; &gt; waiters_; </code></pre> <p>The history of all chat messages -- <code>messages_</code> and all pending <code>get</code> requests that can't be satisfied, because the message still not exists -- <code>waiters_</code></p> <p>Each, "waiter" is actually pointer to request/response context that can be used for message transport.</p> <p>Now, when new message arrives, <code>post</code> member function is called:</p> <pre><code>void post() { if(request().request_method()=="POST") { if(request().post().find("message")!=request().post().end()) { messages_.push_back(request().post().find("message")-&gt;second); broadcast(); } } release_context()-&gt;async_complete_response(); } </code></pre> <p>If the requested message was found, it is added to <code>messages_</code> list and all waiters are notified using <code>broadcast()</code> member function.</p> <p>At the end, the current request context is released and completed.</p> <p>The broadcasting is done as following:</p> <pre><code>void broadcast() { for(unsigned i=0;i&lt;waiters_.size();i++) { waiters_[i]-&gt;response().set_plain_text_header(); waiters_[i]-&gt;response().out() &lt;&lt; messages_.back(); waiters_[i]-&gt;async_complete_response(); waiters_[i]=0; } waiters_.clear(); } </code></pre> <p>For each pending request the last message is written and the request closed. After that, all pending request are cleaned.</p> <p>When <code>get</code> request arrives, it is handled by <code>get(std::string no)</code> member function, first of all we check if requested message exists, if so we just return it to user.</p> <pre><code>unsigned pos=atoi(no.c_str()); if(pos &lt; messages_.size()) { response().set_plain_text_header(); response().out()&lt;&lt;messages_[pos]; release_context()-&gt;async_complete_response(); } </code></pre> <p>Otherwise, if the requested message is the last one, that does not exists, we add the request context to pending list <code>waiters</code></p> <pre><code>else if(pos == messages_.size()) { waiters_.push_back(release_context()); } </code></pre> <p>If requested message it too late -- probably client error, we just set status to "404 Not Found" and return the response.</p> <pre><code>else { response().status(404); release_context()-&gt;async_complete_response(); } </code></pre> <p>No, all we need to do is to add application to the main running loop under script name "/char" and start the service.</p> <pre><code>cppcms::service service(argc,argv); cppcms::intrusive_ptr&lt;chat&gt; app=new chat(service); service.applications_pool().mount(app,"/chat"); service.run(); </code></pre> <h3>Summary</h3> <p>So, the simple chat service was written with about 50 lines of C++ code and about same amount of JavaScript code.</p> <p>I must admit, that it is too simplistic and not efficient, for example: if new client connects it receives all messages one by one and not as bulk (can be easily fixed), I do not handle timeouts and disconnects. But the general idea is quite clear:</p> <ul> <li>Asynchronous long running application that handles <strong>all</strong> request is created.</li> <li>It manages all outstanding request and uses them for server side push.</li> </ul> <p>This is actually a base for future development of tools like XML-RPC and JSON-RPC that allow client to call asynchronously server side objects, it can be used for implementation of any other Comet protocols.</p> </div>