Browse Source

Merge pull request #1180 from stefanocasazza/master

ULib fix - substitute of (#1083 #1122)
Mike Smith 10 years ago
parent
commit
bd8fcdd3bd

+ 7 - 7
frameworks/C++/ULib/README.md

@@ -12,15 +12,15 @@ This is the ULib portion of a [benchmarking test suite](https://github.com/TechE
 
 
 ### Variable Query Test
 ### Variable Query Test
 
 
-* [Variable Query test source](src/queries.usp)
+* [Variable Query test source](src/query.usp)
 
 
 ### Fortune Query Test
 ### Fortune Query Test
 
 
-* [Fortune Query test source](src/fortunes.usp)
+* [Fortune Query test source](src/fortune.usp)
 
 
 ### Variable Query (update) Test
 ### Variable Query (update) Test
 
 
-* [Variable Query (update) test source](src/updates.usp)
+* [Variable Query (update) test source](src/update.usp)
 
 
 ### Plaintext Test
 ### Plaintext Test
 
 
@@ -29,7 +29,7 @@ This is the ULib portion of a [benchmarking test suite](https://github.com/TechE
 ## Infrastructure Software Versions
 ## Infrastructure Software Versions
 The tests were run with:
 The tests were run with:
 
 
-* [ULib Version 1.4.1](https://github.com/stefanocasazza/ULib/archive/v1.4.1.tar.gz)
+* [ULib Version 1.4.2](https://github.com/stefanocasazza/ULib/archive/v1.4.2.tar.gz)
 
 
 Output
 Output
 ======
 ======
@@ -58,7 +58,7 @@ Content-Type: application/json; charset=UTF-8
 {"id":6227,"randomNumber":8489}
 {"id":6227,"randomNumber":8489}
 ```
 ```
 
 
-[/queries?queries=10](http://www.techempower.com/benchmarks/#section=query)
+[/query?queries=10](http://www.techempower.com/benchmarks/#section=query)
 -------------------
 -------------------
 ```
 ```
 HTTP/1.1 200 OK
 HTTP/1.1 200 OK
@@ -70,7 +70,7 @@ Content-Type: application/json; charset=UTF-8
 [{"id":6851,"randomNumber":7598},{"id":3968,"randomNumber":7325},{"id":8159,"randomNumber":348},{"id":9560,"randomNumber":7333},{"id":9938,"randomNumber":9080},{"id":1598,"randomNumber":1623},{"id":3280,"randomNumber":8707},{"id":4521,"randomNumber":6063},{"id":8173,"randomNumber":3690},{"id":3648,"randomNumber":8803}]
 [{"id":6851,"randomNumber":7598},{"id":3968,"randomNumber":7325},{"id":8159,"randomNumber":348},{"id":9560,"randomNumber":7333},{"id":9938,"randomNumber":9080},{"id":1598,"randomNumber":1623},{"id":3280,"randomNumber":8707},{"id":4521,"randomNumber":6063},{"id":8173,"randomNumber":3690},{"id":3648,"randomNumber":8803}]
 ```
 ```
 
 
-[/fortunes](http://www.techempower.com/benchmarks/#section=fortune)
+[/fortune](http://www.techempower.com/benchmarks/#section=fortune)
 ---------
 ---------
 ```
 ```
 HTTP/1.1 200 OK
 HTTP/1.1 200 OK
@@ -82,7 +82,7 @@ Content-Length: 1227
 <!doctype html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><tr><td>11</td><td>&lt;script&gt;alert(&quot;This should not be displayed in a browser alert box.&quot;);&lt;/script&gt;</td></tr><tr><td>4</td><td>A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1</td></tr><tr><td>5</td><td>A computer program does what you tell it to do, not what you want it to do.</td></tr><tr><td>2</td><td>A computer scientist is someone who fixes things that aren&apos;t broken.</td></tr><tr><td>8</td><td>A list is only as strong as its weakest link. — Donald Knuth</td></tr><tr><td>0</td><td>Additional fortune added at request time.</td></tr><tr><td>3</td><td>After enough decimal places, nobody gives a damn.</td></tr><tr><td>7</td><td>Any program that runs right is obsolete.</td></tr><tr><td>10</td><td>Computers make very fast, very accurate mistakes.</td></tr><tr><td>6</td><td>Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen</td></tr><tr><td>9</td><td>Feature: A bug with seniority.</td></tr><tr><td>1</td><td>fortune: No such file or directory</td></tr><tr><td>12</td><td>フレームワークのベンチマーク</td></tr></table></body></html>
 <!doctype html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><tr><td>11</td><td>&lt;script&gt;alert(&quot;This should not be displayed in a browser alert box.&quot;);&lt;/script&gt;</td></tr><tr><td>4</td><td>A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1</td></tr><tr><td>5</td><td>A computer program does what you tell it to do, not what you want it to do.</td></tr><tr><td>2</td><td>A computer scientist is someone who fixes things that aren&apos;t broken.</td></tr><tr><td>8</td><td>A list is only as strong as its weakest link. — Donald Knuth</td></tr><tr><td>0</td><td>Additional fortune added at request time.</td></tr><tr><td>3</td><td>After enough decimal places, nobody gives a damn.</td></tr><tr><td>7</td><td>Any program that runs right is obsolete.</td></tr><tr><td>10</td><td>Computers make very fast, very accurate mistakes.</td></tr><tr><td>6</td><td>Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen</td></tr><tr><td>9</td><td>Feature: A bug with seniority.</td></tr><tr><td>1</td><td>fortune: No such file or directory</td></tr><tr><td>12</td><td>フレームワークのベンチマーク</td></tr></table></body></html>
 ```
 ```
 
 
-[/updates?queries=10](http://www.techempower.com/benchmarks/#section=update)
+[/update?queries=10](http://www.techempower.com/benchmarks/#section=update)
 -------------------
 -------------------
 ```
 ```
 HTTP/1.1 200 OK
 HTTP/1.1 200 OK

+ 1 - 1
frameworks/C++/ULib/bash_profile.sh

@@ -11,6 +11,6 @@
 #    . $FWROOT/toolset/setup/linux/bash_functions.sh && 
 #    . $FWROOT/toolset/setup/linux/bash_functions.sh && 
 #    . $FWROOT/ULib/install.sh (cwd=$FWROOT//installs)
 #    . $FWROOT/ULib/install.sh (cwd=$FWROOT//installs)
 #---------------------------------------------------------------------------------------------------------
 #---------------------------------------------------------------------------------------------------------
-export ULIB_VERSION=1.4.1
+export ULIB_VERSION=1.4.2
 export ULIB_ROOT=$IROOT/ULib
 export ULIB_ROOT=$IROOT/ULib
 export ULIB_DOCUMENT_ROOT=${ULIB_ROOT}/ULIB_DOCUMENT_ROOT
 export ULIB_DOCUMENT_ROOT=${ULIB_ROOT}/ULIB_DOCUMENT_ROOT

+ 28 - 6
frameworks/C++/ULib/benchmark_config

@@ -1,23 +1,45 @@
 {
 {
   "framework": "ULib",
   "framework": "ULib",
   "tests": [{
   "tests": [{
-    "default": {
+    "sqlite": {
       "setup_file": "setup",
       "setup_file": "setup",
       "json_url": "/json",
       "json_url": "/json",
       "db_url": "/db",
       "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?queries=",
+      "query_url": "/query?queries=",
+      "fortune_url": "/fortune",
       "plaintext_url": "/plaintext",
       "plaintext_url": "/plaintext",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
-      "classification": "Fullstack",
+      "classification": "Platform",
+      "database": "SQLite",
+      "framework": "ULib",
+      "language": "C++",
+      "orm": "Micro",
+      "platform": "ULib",
+      "webserver": "userver_tcp",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "ULib",
+      "notes": "",
+      "versus": ""
+    },
+    "mysql": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/query?queries=",
+      "fortune_url": "/fortune",
+      "plaintext_url": "/plaintext",
+      "update_url": "/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
       "database": "MySQL",
       "database": "MySQL",
       "framework": "ULib",
       "framework": "ULib",
       "language": "C++",
       "language": "C++",
       "orm": "Micro",
       "orm": "Micro",
       "platform": "ULib",
       "platform": "ULib",
-      "webserver": "None",
+      "webserver": "userver_tcp",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "ULib",
       "display_name": "ULib",

+ 19 - 10
frameworks/C++/ULib/install.sh

@@ -2,7 +2,8 @@
 
 
 # install.sh
 # install.sh
 # --------------------------------------------------------------------------------------------------------
 # --------------------------------------------------------------------------------------------------------
-# toolset/run-tests.py --install server --test ULib --type all --verbose
+# toolset/run-tests.py --install server --test ULib-mysql  --type all --verbose
+# toolset/run-tests.py --install server --test ULib-sqlite --type all --verbose
 # --------------------------------------------------------------------------------------------------------
 # --------------------------------------------------------------------------------------------------------
 # TROOT - Path of this test's directory
 # TROOT - Path of this test's directory
 # IROOT - Path of this test's install directory ($FWROOT/installs or $FWROOT/installs/pertest/<test-name>)
 # IROOT - Path of this test's install directory ($FWROOT/installs or $FWROOT/installs/pertest/<test-name>)
@@ -15,11 +16,18 @@
 #    . $FWROOT/ULib/install.sh (cwd=$FWROOT//installs)
 #    . $FWROOT/ULib/install.sh (cwd=$FWROOT//installs)
 # --------------------------------------------------------------------------------------------------------
 # --------------------------------------------------------------------------------------------------------
 
 
-# Chekc if ULib is already installed
-RETCODE=$(fw_exists ulib-${ULIB_VERSION}.installed)
+# Check if ULib is already installed
+ULIB_INSTALLED_FILE="${IROOT}/ULib-${ULIB_VERSION}.installed"
+RETCODE=$(fw_exists ${ULIB_INSTALLED_FILE})
 [ ! "$RETCODE" == 0 ] || { return 0; }
 [ ! "$RETCODE" == 0 ] || { return 0; }
 
 
+# ULib is only built during installation as a dependency sanity check
+#sudo apt-get update
+ sudo apt-get install libmysqlclient-dev libsqlite3-dev
+
 # Create a run directory for ULIB
 # Create a run directory for ULIB
+[ ! -e ${ULIB_INSTALLED_FILE} -a -d ${IROOT}/ULib ] && rm -rf ${IROOT}/ULib*
+
 if [ ! -d "$ULIB_ROOT" ]; then
 if [ ! -d "$ULIB_ROOT" ]; then
   mkdir -p $ULIB_ROOT
   mkdir -p $ULIB_ROOT
 fi
 fi
@@ -42,7 +50,7 @@ fi
 # 1. Download ULib
 # 1. Download ULib
 cd $IROOT
 cd $IROOT
 fw_get -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz 
 fw_get -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz 
-fw_untar ULib-${ULIB_VERSION}.tar.gz
+fw_untar  ULib-${ULIB_VERSION}.tar.gz
 
 
 # 2. Compile application (userver_tcp)
 # 2. Compile application (userver_tcp)
 
 
@@ -51,19 +59,18 @@ cd ULib-$ULIB_VERSION
 # AVOID "configure: error: newly created file is older than distributed files! Check your system clock"
 # AVOID "configure: error: newly created file is older than distributed files! Check your system clock"
 find . -exec touch {} \;
 find . -exec touch {} \;
 
 
-LIBS="-lssl -lcrypto -lz" \
 ./configure --prefix=$ULIB_ROOT \
 ./configure --prefix=$ULIB_ROOT \
             --disable-static \
             --disable-static \
-            --with-mysql \
+            --with-mysql --with-sqlite3 \
             --without-ssl --without-pcre --without-expat \
             --without-ssl --without-pcre --without-expat \
             --without-libz --without-libuuid --without-magic \
             --without-libz --without-libuuid --without-magic \
-            --enable-static-orm-driver=mysql --enable-static-server-plugin=http
+            --enable-static-orm-driver='mysql sqlite' --enable-static-server-plugin=http
 #           --enable-debug \
 #           --enable-debug \
 make install
 make install
 
 
 # 3. Compile usp pages for benchmark
 # 3. Compile usp pages for benchmark
 cd src/ulib/net/server/plugin/usp
 cd src/ulib/net/server/plugin/usp
-make db.la fortunes.la json.la plaintext.la queries.la updates.la
+make db.la fortune.la json.la plaintext.la query.la update.la
 
 
 # Check that compilation worked
 # Check that compilation worked
 if [ ! -e .libs/db.so ]; then
 if [ ! -e .libs/db.so ]; then
@@ -71,7 +78,9 @@ if [ ! -e .libs/db.so ]; then
 fi
 fi
 
 
 mkdir -p $ULIB_DOCUMENT_ROOT
 mkdir -p $ULIB_DOCUMENT_ROOT
-cp .libs/db.so .libs/fortunes.so .libs/json.so .libs/plaintext.so .libs/queries.so .libs/updates.so $ULIB_DOCUMENT_ROOT
+cp .libs/db.so .libs/fortune.so .libs/json.so .libs/plaintext.so .libs/query.so .libs/update.so $ULIB_DOCUMENT_ROOT
 
 
 cd $IROOT
 cd $IROOT
-touch ulib-${ULIB_VERSION}.installed 
+cp -r ULib-1.4.2/tests/examples/benchmark/FrameworkBenchmarks/ULib/db $ULIB_ROOT
+
+touch ${ULIB_INSTALLED_FILE}

+ 19 - 31
frameworks/C++/ULib/setup.py

@@ -5,50 +5,38 @@ import setup_util
 import subprocess
 import subprocess
 import multiprocessing
 import multiprocessing
 
 
-def start(args, logfile, errfile):
-
-  fwroot = args.fwroot
+def get_env_for_database(args):
+  if args.database == 'MySQL':
+     driver = 'mysql'
+     dbname = 'hello_world'
+  else:
+     driver = 'sqlite'
+     dbname = os.environ['ULIB_ROOT'] + '/db/%.*s'
+  return {
+      'UMEMPOOL': '135,0,0,34,8465,129,-17,-22,41',
+      'ORM_DRIVER': driver,
+      'ORM_OPTION': "host=" + args.database_host + " user=benchmarkdbuser password=benchmarkdbpass character-set=utf8 dbname=" + dbname
+    }
 
 
+def start(args, logfile, errfile):
   try:
   try:
-    ulib_root = subprocess.check_output('printf $ULIB_ROOT', shell=True, stderr=errfile)
-
+    ulib_root = os.environ['ULIB_ROOT']
     fcfg = ulib_root + "/benchmark.cfg"
     fcfg = ulib_root + "/benchmark.cfg"
-
-    # 1. Change ULib Server configuration
-
-    # I don't understand if the two approach are different...
-    #threads = str(args.max_threads)
-    PROCS = str(multiprocessing.cpu_count())
-    setup_util.replace_text(fcfg, "PREFORK_CHILD .*", "PREFORK_CHILD " + PROCS)
-
     fprg = ulib_root + "/bin/userver_tcp"
     fprg = ulib_root + "/bin/userver_tcp"
-
+    # 1. Change ULib Server configuration
+    setup_util.replace_text(fcfg, "PREFORK_CHILD .*", "PREFORK_CHILD " + str(multiprocessing.cpu_count()))
     # 2. Start ULib Server (userver_tcp)
     # 2. Start ULib Server (userver_tcp)
-    logfile.write("ULib: trying to start server %s -c %s\n" % (fprg, fcfg))
-
-    # sudo mysqlcheck -v -r -A -u benchmarkdbuser -p
-    os.putenv("ORM_DRIVER","mysql")
-    os.putenv("ORM_OPTION","host=" + args.database_host + " user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world")
-    os.putenv("UMEMPOOL", "1583,1507,-19,45,16458,523,-27,-14,27")
-
-    # Run in the background, but keep stdout/stderr for easy debugging
-    subprocess.Popen( "%s -c %s" % (fprg, fcfg), shell=True, stdout=logfile, stderr=errfile)
-    # subprocess.Popen("UTRACE=\"0 50M\" " + fprg + " -c " + fcfg, shell=True, stdout=logfile, stderr=errfile)
-
-    logfile.write("ULib: server STARTED\n")
+    subprocess.Popen( "%s -c %s" % (fprg, fcfg), shell=True, stdout=logfile, stderr=errfile, env = get_env_for_database(args))
     return 0
     return 0
   except subprocess.CalledProcessError:
   except subprocess.CalledProcessError:
     return 1
     return 1
 
 
 def stop(logfile, errfile):
 def stop(logfile, errfile):
   try:
   try:
-    logfile.write( "ULib: setup.py STOP\n")
-
-
     # Stop ULib Server (userver_tcp)
     # Stop ULib Server (userver_tcp)
     subprocess.check_call("kill -TERM $( cat $ULIB_ROOT/userver_tcp.pid )", shell=True, stderr=errfile, stdout=logfile)
     subprocess.check_call("kill -TERM $( cat $ULIB_ROOT/userver_tcp.pid )", shell=True, stderr=errfile, stdout=logfile)
-    time.sleep(2);
-    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+    time.sleep(3);
+    p = subprocess.Popen(['pgrep', 'userver_tcp'], stdout=subprocess.PIPE)
     out, err = p.communicate()
     out, err = p.communicate()
     for line in out.splitlines():
     for line in out.splitlines():
        if 'userver_tcp' in line:
        if 'userver_tcp' in line:

+ 3 - 3
frameworks/C++/ULib/source_code

@@ -2,7 +2,7 @@
 ./src/world.h
 ./src/world.h
 ./src/json.usp
 ./src/json.usp
 ./src/fortune.h
 ./src/fortune.h
-./src/queries.usp
-./src/updates.usp
-./src/fortunes.usp
+./src/query.usp
+./src/update.usp
+./src/fortune.usp
 ./src/plaintext.usp
 ./src/plaintext.usp

+ 23 - 81
frameworks/C++/ULib/src/db.usp

@@ -1,106 +1,48 @@
-<!--#
-Test 2: Single database query
-
-This test exercises the framework's object-relational mapper (ORM), random number generator, database driver, and database connection pool.
-
-Requirements
-
-1.  For every request, a single row from a World table must be retrieved from a database table. 
-
-2.  The recommended URI is /db.
-
-3.  The schema for World is id (int, primary key) and randomNumber (int).
-
-4.  The World table is known to contain 10,000 rows.
-
-5.  The row retrieved must be selected by its id using a random number generator (ids range from 1 to 10,000).
-
-6.  The row should be converted to an object using an object-relational mapping (ORM) tool.
-    Tests that do not use an ORM will be identified with the suffix "raw," meaning they use the platform's raw database connectivity.
-
-7.  The object (or database row, if an ORM is not used) must be serialized to JSON.
-
-8.  The response content length should be approximately 32 bytes.
-
-9.  The response content type must be set to application/json.
-
-10. The response headers must include either Content-Length or Transfer-Encoding.
-
-11. The response headers must include Server and Date.
-
-12. Use of an in-memory cache of World objects or rows by the application is not permitted.
-
-13. Use of prepared statements for SQL database tests (e.g., for MySQL) is encouraged but not required.
-
-14. gzip compression is not permitted.
-
-15. Server support for HTTP Keep-Alive is strongly encouraged but not required.
-
-16. If HTTP Keep-Alive is enabled, no maximum Keep-Alive timeout is specified by this test.
-
-17. The request handler will be exercised at concurrency levels ranging from 8 to 256.
-
-18. The request handler will be exercised using GET requests.
-
-Example request:
-
-GET /db HTTP/1.1
-Host: server
-User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00
-Cookie: uid=12345678901234567890; __utma=1.1234567890.1234567890.1234567890.1234567890.12; wd=2560x1600
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-US,en;q=0.5
-Connection: keep-alive
-
-Example response:
-
-HTTP/1.1 200 OK
-Content-Type: application/json; charset=UTF-8
-Content-Length: 32
-Server: Example
-Date: Wed, 17 Apr 2013 12:00:00 GMT
-{"id":3217,"randomNumber":2149}
--->
 <!--#declaration
 <!--#declaration
 #include "world.h"
 #include "world.h"
 
 
 #define AS_cpoll_cppsp_DO
 #define AS_cpoll_cppsp_DO
 
 
 #ifndef AS_cpoll_cppsp_DO
 #ifndef AS_cpoll_cppsp_DO
-static UValue*	pvalue;
+static UValue* pvalue;
 #endif
 #endif
-static World*			 pworld_db;
-static UOrmSession*	 psql_db;
+static World*         pworld_db;
+static UOrmSession*   psql_db;
 static UOrmStatement* pstmt_db;
 static UOrmStatement* pstmt_db;
 
 
 static void usp_init_db()
 static void usp_init_db()
 {
 {
-	U_TRACE(5, "::usp_init_db()")
+   U_TRACE(5, "::usp_init_db()")
+
+   pworld_db = U_NEW(World);
 
 
-	psql_db	= U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("hello_world")));
-	pstmt_db	= U_NEW(UOrmStatement(*psql_db, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
+#ifndef AS_cpoll_cppsp_DO
+   pvalue = U_NEW(UValue(OBJECT_VALUE));
+#endif
+}
 
 
-	if (pstmt_db == 0) U_ERROR("usp_init_db(): we cound't connect to db, exiting...");
+static void usp_fork_db()
+{
+   U_TRACE(5, "::usp_fork_db()")
 
 
-	pworld_db = U_NEW(World);
+   psql_db  = U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("hello_world")));
+   pstmt_db = U_NEW(UOrmStatement(*psql_db, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
 
 
-	pstmt_db->use( pworld_db->id);
-	pstmt_db->into(pworld_db->randomNumber);
+   if (pstmt_db == 0) U_ERROR("usp_fork_db(): we cound't connect to db, exiting...");
 
 
-#ifndef AS_cpoll_cppsp_DO
-	pvalue = U_NEW(UValue(OBJECT_VALUE));
-#endif
+   pstmt_db->use( pworld_db->id);
+   pstmt_db->into(pworld_db->randomNumber);
 }
 }
 
 
 static void usp_end_db()
 static void usp_end_db()
 {
 {
-	U_TRACE(5, "::usp_end_db()")
+   U_TRACE(5, "::usp_end_db()")
 
 
-	delete pstmt_db;
-	delete psql_db;
-	delete pworld_db;
+   delete pstmt_db;
+   delete psql_db;
+   delete pworld_db;
 #ifndef AS_cpoll_cppsp_DO
 #ifndef AS_cpoll_cppsp_DO
-	delete pvalue;
+   delete pvalue;
 #endif
 #endif
 }
 }
 -->
 -->

+ 70 - 70
frameworks/C++/ULib/src/fortune.h

@@ -8,116 +8,116 @@
 
 
 class Fortune {
 class Fortune {
 public:
 public:
-	// Check for memory error
-	U_MEMORY_TEST
+   // Check for memory error
+   U_MEMORY_TEST
 
 
-	// Allocator e Deallocator
-	U_MEMORY_ALLOCATOR
-	U_MEMORY_DEALLOCATOR
+   // Allocator e Deallocator
+   U_MEMORY_ALLOCATOR
+   U_MEMORY_DEALLOCATOR
 
 
-	int id;
-	UString message;
+   int id;
+   UString message;
 
 
-	// CONSTRUCTOR
+   // CONSTRUCTOR
 
 
-	Fortune()
-		{
-		U_TRACE_REGISTER_OBJECT(5, Fortune, "")
-		}
+   Fortune()
+      {
+      U_TRACE_REGISTER_OBJECT(5, Fortune, "")
+      }
 
 
-	Fortune(int _id, const UString& _message) : id(_id), message(_message)
-		{
-		U_TRACE_REGISTER_OBJECT(5, Fortune, "%d,%.*S", _id, U_STRING_TO_TRACE(_message))
-		}
+   Fortune(int _id, const UString& _message) : id(_id), message(_message)
+      {
+      U_TRACE_REGISTER_OBJECT(5, Fortune, "%d,%.*S", _id, U_STRING_TO_TRACE(_message))
+      }
 
 
-	Fortune(const Fortune& f) : id(f.id), message((void*)U_STRING_TO_PARAM(f.message))
-		{
-		U_TRACE_REGISTER_OBJECT(5, Fortune, "%p", &f)
+   Fortune(const Fortune& f) : id(f.id), message((void*)U_STRING_TO_PARAM(f.message))
+      {
+      U_TRACE_REGISTER_OBJECT(5, Fortune, "%p", &f)
 
 
-		U_MEMORY_TEST_COPY(f)
-		}
+      U_MEMORY_TEST_COPY(f)
+      }
 
 
-	~Fortune()
-		{
-		U_TRACE_UNREGISTER_OBJECT(5, Fortune)
-		}
+   ~Fortune()
+      {
+      U_TRACE_UNREGISTER_OBJECT(5, Fortune)
+      }
 
 
-	// SERVICE
+   // SERVICE
 
 
-	bool operator<(const Fortune& other) const { return cmp_obj(&message, &other.message); }
+   bool operator<(const Fortune& other) const { return cmp_obj(&message, &other.message); }
 
 
-	static int cmp_obj(const void* a, const void* b)
-		{
-		U_TRACE(5, "Fortune::cmp_obj(%p,%p)", a, b)
+   static int cmp_obj(const void* a, const void* b)
+      {
+      U_TRACE(5, "Fortune::cmp_obj(%p,%p)", a, b)
 
 
-		return (*(const Fortune**)a)->message.compare((*(const Fortune**)b)->message);
-		}
+      return (*(const Fortune**)a)->message.compare((*(const Fortune**)b)->message);
+      }
 
 
 #ifdef DEBUG
 #ifdef DEBUG
-	const char* dump(bool breset) const
-		{
-		*UObjectIO::os << "id               " << id				   << '\n'
-							<< "message (UString " << (void*)&message << ')';
+   const char* dump(bool breset) const
+      {
+      *UObjectIO::os << "id               " << id              << '\n'
+                     << "message (UString " << (void*)&message << ')';
 
 
-		if (breset)
-			{
-			UObjectIO::output();
+      if (breset)
+         {
+         UObjectIO::output();
 
 
-			return UObjectIO::buffer_output;
-			}
+         return UObjectIO::buffer_output;
+         }
 
 
-		return 0;
-		}
+      return 0;
+      }
 #endif
 #endif
 
 
 private:
 private:
-	Fortune& operator=(const Fortune&) { return *this; }
+   Fortune& operator=(const Fortune&) { return *this; }
 };
 };
 
 
 // ORM TEMPLATE SPECIALIZATIONS
 // ORM TEMPLATE SPECIALIZATIONS
 
 
 template <> class U_EXPORT UOrmTypeHandler<Fortune> : public UOrmTypeHandler_Base {
 template <> class U_EXPORT UOrmTypeHandler<Fortune> : public UOrmTypeHandler_Base {
 public:
 public:
-	explicit UOrmTypeHandler(Fortune& val) : UOrmTypeHandler_Base(&val) {}
+   explicit UOrmTypeHandler(Fortune& val) : UOrmTypeHandler_Base(&val) {}
 
 
-	void bindParam(UOrmStatement* stmt) const
-		{
-		U_TRACE(0, "UOrmTypeHandler<Fortune>::bindParam(%p)", stmt)
+   void bindParam(UOrmStatement* stmt) const
+      {
+      U_TRACE(0, "UOrmTypeHandler<Fortune>::bindParam(%p)", stmt)
 
 
-		stmt->bindParam(U_ORM_TYPE_HANDLER(Fortune, id,		  int));
-		stmt->bindParam(U_ORM_TYPE_HANDLER(Fortune, message, UString));
-		}
+      stmt->bindParam(U_ORM_TYPE_HANDLER(Fortune, id,      int));
+      stmt->bindParam(U_ORM_TYPE_HANDLER(Fortune, message, UString));
+      }
 
 
-	void bindResult(UOrmStatement* stmt)
-		{
-		U_TRACE(0, "UOrmTypeHandler<Fortune>::bindResult(%p)", stmt)
+   void bindResult(UOrmStatement* stmt)
+      {
+      U_TRACE(0, "UOrmTypeHandler<Fortune>::bindResult(%p)", stmt)
 
 
-		stmt->bindResult(U_ORM_TYPE_HANDLER(Fortune, id,		int));
-		stmt->bindResult(U_ORM_TYPE_HANDLER(Fortune, message, UString));
-		}
+      stmt->bindResult(U_ORM_TYPE_HANDLER(Fortune, id,      int));
+      stmt->bindResult(U_ORM_TYPE_HANDLER(Fortune, message, UString));
+      }
 };
 };
 
 
 // JSON TEMPLATE SPECIALIZATIONS
 // JSON TEMPLATE SPECIALIZATIONS
 
 
 template <> class U_EXPORT UJsonTypeHandler<Fortune> : public UJsonTypeHandler_Base {
 template <> class U_EXPORT UJsonTypeHandler<Fortune> : public UJsonTypeHandler_Base {
 public:
 public:
-	explicit UJsonTypeHandler(Fortune& val) : UJsonTypeHandler_Base(&val) {}
+   explicit UJsonTypeHandler(Fortune& val) : UJsonTypeHandler_Base(&val) {}
 
 
-	void toJSON(UValue& json)
-		{
-		U_TRACE(0, "UJsonTypeHandler<Fortune>::toJSON(%p)", &json)
+   void toJSON(UValue& json)
+      {
+      U_TRACE(0, "UJsonTypeHandler<Fortune>::toJSON(%p)", &json)
 
 
-		json.toJSON(U_JSON_TYPE_HANDLER(Fortune, id,		  int));
-		json.toJSON(U_JSON_TYPE_HANDLER(Fortune, message, UString));
-		}
+      json.toJSON(U_JSON_TYPE_HANDLER(Fortune, id,      int));
+      json.toJSON(U_JSON_TYPE_HANDLER(Fortune, message, UString));
+      }
 
 
-	void fromJSON(UValue& json)
-		{
-		U_TRACE(0, "UJsonTypeHandler<Fortune>::fromJSON(%p)", &json)
+   void fromJSON(UValue& json)
+      {
+      U_TRACE(0, "UJsonTypeHandler<Fortune>::fromJSON(%p)", &json)
 
 
-		json.fromJSON(U_JSON_TYPE_HANDLER(Fortune, id,		 int));
-		json.fromJSON(U_JSON_TYPE_HANDLER(Fortune, message, UString));
-		}
+      json.fromJSON(U_JSON_TYPE_HANDLER(Fortune, id,      int));
+      json.fromJSON(U_JSON_TYPE_HANDLER(Fortune, message, UString));
+      }
 };
 };
 
 
 #endif
 #endif

+ 68 - 0
frameworks/C++/ULib/src/fortune.usp

@@ -0,0 +1,68 @@
+<!--#declaration
+#include "fortune.h"
+
+static UOrmSession*       psql_fortune;
+static UOrmStatement*     pstmt_fortune;
+static Fortune*           pfortune;
+static UString*           pmessage;
+static UVector<Fortune*>* pvfortune;
+
+static void usp_init_fortune()
+{
+   U_TRACE(5, "::usp_init_fortune()")
+
+   pfortune  = U_NEW(Fortune);
+   pvfortune = U_NEW(UVector<Fortune*>);
+   pmessage  = U_NEW(U_STRING_FROM_CONSTANT("Additional fortune added at request time."));
+}
+
+static void usp_fork_fortune()
+{
+   U_TRACE(5, "::usp_fork_fortune()")
+
+   psql_fortune  = U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("fortune")));
+   pstmt_fortune = U_NEW(UOrmStatement(*psql_fortune, U_CONSTANT_TO_PARAM("SELECT id, message FROM Fortune")));
+
+   if (pstmt_fortune == 0) U_ERROR("usp_fork_fortune(): we cound't connect to db, exiting...");
+
+   pstmt_fortune->into(*pfortune);
+}
+
+static void usp_end_fortune()
+{
+   U_TRACE(5, "::usp_end_fortune()")
+
+   delete pstmt_fortune;
+   delete psql_fortune;
+   delete pvfortune;
+   delete pfortune;
+   delete pmessage;
+}
+-->
+<!doctype html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><!--#code
+Fortune* elem;
+unsigned char encoded[1024];
+
+pstmt_fortune->execute();
+
+     pvfortune->push_back(U_NEW(Fortune(0, *pmessage)));
+do { pvfortune->push_back(U_NEW(Fortune(*pfortune))); } while (pstmt_fortune->nextRow());
+
+pvfortune->sort(Fortune::cmp_obj);
+
+for (uint32_t i = 0, n = pvfortune->size(); i < n; ++i)
+   {
+   elem = (*pvfortune)[i];
+
+   (void) u_xml_encode((const unsigned char*)U_STRING_TO_PARAM(elem->message), encoded);
+
+   USP_PRINTF_ADD(
+      "<tr>"
+      "<td>%d</td>"
+      "<td>%s</td>"
+      "</tr>",
+      elem->id, encoded);
+   }
+
+pvfortune->clear();
+--></table></body></html>

+ 0 - 153
frameworks/C++/ULib/src/fortunes.usp

@@ -1,153 +0,0 @@
-<!--#
-Test 4: Fortunes
-
-This test exercises the ORM, database connectivity, dynamic-size collections,
-sorting, server-side templates, XSS countermeasures, and character encoding.
-
-Requirements
-
-1.  The recommended URI is /fortunes.
-
-2.  A Fortune database table contains a dozen Unix-style fortune-cookie messages.
-
-3.  The schema for Fortune is id (int, primary key) and message (varchar).
-
-4.  Using an ORM, all Fortune objects must be fetched from the Fortune table, and placed into a list data structure.
-    Tests that do not use an ORM will be classified as "raw" meaning they use the platform's raw database connectivity.
-
-5.  The list data structure must be a dynamic-size or equivalent and should not be dimensioned using foreknowledge of
-    the row-count of the database table.
-
-6.  Within the scope of the request, a new Fortune object must be constructed and added to the list. This confirms that
-    the data structure is dynamic-sized. The new fortune is not persisted to the database; it is ephemeral for the scope of the request.
-
-7.  The new Fortune's message must be "Additional fortune added at request time."
-
-8.  The list of Fortune objects must be sorted by the order of the message field. No ORDER BY clause is permitted in the
-    database query (ordering within the query would be of negligible value anyway since a newly instantiated Fortune is
-	 added to the list prior to sorting).
-
-9.  The sorted list must be provided to a server-side template and rendered to simple HTML (see below for minimum template).
-    The resulting HTML table displays each Fortune's id number and message text.
-
-10. This test does not include external assets (CSS, JavaScript); a later test type will include assets.
-
-11. The HTML generated by the template must be sent as a response.
-
-12. Be aware that the message text fields are stored as UTF-8 and one of the fortune cookie messages is in Japanese.
-
-13. The resulting HTML must be delivered using UTF-8 encoding.
-
-14. The Japanese fortune cookie message must be displayed correctly.
-
-15. Be aware that at least one of the message text fields includes a <script> tag.
-
-16. The server-side template must assume the message text cannot be trusted and must escape the message text properly.
-
-17. The implementation is encouraged to use best practices for templates such as layout inheritence, separate header and
-    footer files, and so on. However, this is not required. We request that implementations do not manage assets (JavaScript,
-	 CSS, images). We are deferring asset management until we can craft a more suitable test.
-
-18. The response content type must be set to text/html.
-
-19. The response headers must include either Content-Length or Transfer-Encoding.
-
-20. The response headers must include Server and Date.
-
-21. Use of an in-memory cache of Fortune objects or rows by the application is not permitted.
-
-22. Use of prepared statements for SQL database tests (e.g., for MySQL) is encouraged but not required.
-
-23. gzip compression is not permitted.
-
-24. Server support for HTTP Keep-Alive is strongly encouraged but not required.
-
-25. If HTTP Keep-Alive is enabled, no maximum Keep-Alive timeout is specified by this test.
-
-26. The request handler will be exercised at concurrency levels ranging from 8 to 256.
-
-27. The request handler will be exercised using GET requests.
-
-Example request:
-
-GET /fortunes HTTP/1.1
-Host: server
-User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00
-Cookie: uid=12345678901234567890; __utma=1.1234567890.1234567890.1234567890.1234567890.12; wd=2560x1600
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-US,en;q=0.5
-Connection: keep-alive
-
-Example response:
-
-HTTP/1.1 200 OK
-Content-Length: 1190
-Content-Type: text/html; charset=UTF-8
-Server: Example
-Date: Wed, 17 Apr 2013 12:00:00 GMT
-
-<!doctype html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><tr><td>11</td><td>&lt;script&gt;alert(&quot;This should not be displayed in a browser alert box.&quot;);&lt;/script&gt;</td></tr><tr><td>4</td><td>A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1</td></tr><tr><td>5</td><td>A computer program does what you tell it to do, not what you want it to do.</td></tr><tr><td>2</td><td>A computer scientist is someone who fixes things that aren't broken.</td></tr><tr><td>8</td><td>A list is only as strong as its weakest link. â Donald Knuth</td></tr><tr><td>0</td><td>Additional fortune added at request time.</td></tr><tr><td>3</td><td>After enough decimal places, nobody gives a damn.</td></tr><tr><td>7</td><td>Any program that runs right is obsolete.</td></tr><tr><td>10</td><td>Computers make very fast, very accurate mistakes.</td></tr><tr><td>6</td><td>Emacs is a nice operating system, but I prefer UNIX. â Tom Christaensen</td></tr><tr><td>9</td><td>Feature: A bug with seniority.</td></tr><tr><td>1</td><td>fortune: No such file or directory</td></tr><tr><td>12</td><td>ã¬ã¼ãã¯ã¼ã¯ã®ãã³ããã¼ã¯</td></tr></table></body></html>
--->
-<!--#declaration
-#include "fortune.h"
-
-static UOrmSession*		  psql_fortune;
-static UOrmStatement*	  pstmt_fortune;
-static Fortune*			  pfortune;
-static UString*           pmessage;
-static UVector<Fortune*>* pvfortune;
-
-static void usp_init_fortunes()
-{
-	U_TRACE(5, "::usp_init_fortunes()")
-
-	psql_fortune  = U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("fortune")));
-	pstmt_fortune = U_NEW(UOrmStatement(*psql_fortune, U_CONSTANT_TO_PARAM("SELECT id, message FROM Fortune")));
-
-	if (pstmt_fortune == 0) U_ERROR("usp_init_fortunes(): we cound't connect to db, exiting...");
-
-	pfortune  = U_NEW(Fortune);
-	pvfortune = U_NEW(UVector<Fortune*>);
-	pmessage  = U_NEW(U_STRING_FROM_CONSTANT("Additional fortune added at request time."));
-
-	pstmt_fortune->into(*pfortune);
-}
-
-static void usp_end_fortunes()
-{
-	U_TRACE(5, "::usp_end_fortunes()")
-
-	delete pstmt_fortune;
-	delete psql_fortune;
-	delete pvfortune;
-	delete pfortune;
-	delete pmessage;
-}
--->
-<!doctype html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><!--#code
-Fortune* elem;
-unsigned char encoded[1024];
-
-pstmt_fortune->execute();
-
-	  pvfortune->push_back(U_NEW(Fortune(0, *pmessage)));
-do	{ pvfortune->push_back(U_NEW(Fortune(*pfortune))); } while (pstmt_fortune->nextRow());
-
-pvfortune->sort(Fortune::cmp_obj);
-
-for (uint32_t i = 0, n = pvfortune->size(); i < n; ++i)
-	{
-	elem = (*pvfortune)[i];
-
-	(void) u_xml_encode((const unsigned char*)U_STRING_TO_PARAM(elem->message), encoded);
-
-	USP_PRINTF_ADD(
-		"<tr>"
-		"<td>%d</td>"
-		"<td>%s</td>"
-		"</tr>",
-		elem->id, encoded);
-	}
-
-pvfortune->clear();
---></table></body></html>

+ 6 - 59
frameworks/C++/ULib/src/json.usp

@@ -1,74 +1,21 @@
-<!--#
-Test 1: JSON serialization
-
-This test exercises the framework fundamentals including keep-alive support, request routing, request header
-parsing, object instantiation, JSON serialization, response header generation, and request count throughput.
-
-Requirements
-
-1.  For each request, an object mapping the key message to Hello, World! must be instantiated.
-
-2.  The recommended URI is /json.
-
-3.  A JSON serializer must be used to convert the object to JSON.
-
-4.  The response text must be {"message":"Hello, World!"}, but white-space variations are acceptable.
-
-5.  The response content length should be approximately 28 bytes.
-
-6.  The response content type must be set to application/json.
-
-7.  The response headers must include either Content-Length or Transfer-Encoding.
-
-8.  The response headers must include Server and Date.
-
-9.  gzip compression is not permitted.
-
-10. Server support for HTTP Keep-Alive is strongly encouraged but not required.
-
-11. If HTTP Keep-Alive is enabled, no maximum Keep-Alive timeout is specified by this test.
-
-12. The request handler will be exercised at concurrency levels ranging from 8 to 256.
-
-13. The request handler will be exercised using GET requests.
-
-Example request:
-
-GET /json HTTP/1.1
-Host: server
-User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00
-Cookie: uid=12345678901234567890; __utma=1.1234567890.1234567890.1234567890.1234567890.12; wd=2560x1600
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-US,en;q=0.5
-Connection: keep-alive
-
-Example response:
-
-HTTP/1.1 200 OK
-Content-Type: application/json; charset=UTF-8
-Content-Length: 28
-Server: Example
-Date: Wed, 17 Apr 2013 12:00:00 GMT
-{"message":"Hello, World!"}
--->
 <!--#declaration
 <!--#declaration
 static UString* pkey;
 static UString* pkey;
 static UString* pvalue;
 static UString* pvalue;
 
 
 static void usp_init_json()
 static void usp_init_json()
 {
 {
-	U_TRACE(5, "::usp_init_json()")
+   U_TRACE(5, "::usp_init_json()")
 
 
-	pkey   = U_NEW(U_STRING_FROM_CONSTANT("message"));
-	pvalue = U_NEW(U_STRING_FROM_CONSTANT("Hello, World!"));
+   pkey   = U_NEW(U_STRING_FROM_CONSTANT("message"));
+   pvalue = U_NEW(U_STRING_FROM_CONSTANT("Hello, World!"));
 }
 }
 
 
 static void usp_end_json()
 static void usp_end_json()
 {
 {
-	U_TRACE(5, "::usp_end_json()")
+   U_TRACE(5, "::usp_end_json()")
 
 
-	delete pkey;
-	delete pvalue;
+   delete pkey;
+   delete pvalue;
 }
 }
 -->
 -->
 <!--#header
 <!--#header

+ 0 - 50
frameworks/C++/ULib/src/plaintext.usp

@@ -1,51 +1 @@
-<!--#
-Test 6: Plaintext
-
-This test is an exercise of the request-routing fundamentals only, designed to demonstrate the capacity of
-high-performance platforms in particular. The response payload is still small, meaning good performance is
-still necessary in order to saturate the gigabit Ethernet of the test environment.
-
-Requirements
-
-1.  The recommended URI is /plaintext.
-
-2.  The response content type must be set to text/plain.
-
-3.  The response body must be Hello, World!.
-
-4.  The response headers must include either Content-Length or Transfer-Encoding.
-
-5.  The response headers must include Server and Date.
-
-6.  gzip compression is not permitted.
-
-7.  Server support for HTTP Keep-Alive is strongly encouraged but not required.
-
-8.  Server support for HTTP pipelining is strongly encouraged but not required.
-
-9.  If HTTP Keep-Alive is enabled, no maximum Keep-Alive timeout is specified by this test.
-
-10. The request handler will be exercised at 256, 1024, 4096, and 16,384 concurrency.
-
-11. The request handler will be exercised using GET requests.
-
-Example request:
-
-GET /plaintext HTTP/1.1
-Host: server
-User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00
-Cookie: uid=12345678901234567890; __utma=1.1234567890.1234567890.1234567890.1234567890.12; wd=2560x1600
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-US,en;q=0.5
-Connection: keep-alive
-
-Example response:
-
-HTTP/1.1 200 OK
-Content-Length: 15
-Content-Type: text/plain; charset=UTF-8
-Server: Example
-Date: Wed, 17 Apr 2013 12:00:00 GMT
-Hello, World!
--->
 Hello, World!
 Hello, World!

+ 0 - 160
frameworks/C++/ULib/src/queries.usp

@@ -1,160 +0,0 @@
-<!--#
-Test 3: Multiple database queries
-
-This test is a variation of Test #2 and also uses the World table. Multiple rows are fetched to more dramatically
-punish the database driver and connection pool. At the highest queries-per-request tested (20), this test demonstrates
-all frameworks' convergence toward zero requests-per-second as database activity increases.
-
-Requirements
-
-1.  For every request, an integer query string parameter named queries must be retrieved from the request.
-	 The parameter specifies the number of database queries to execute in preparing the HTTP response (see below).
-
-2.  The recommended URI is /queries.
-
-3.  The queries parameter must be bounded to between 1 and 500. If the parameter is missing, is not an integer,
-	 or is an integer less than 1, the value should be interpreted as 1; if greater than 500, the value should be interpreted as 500.
-
-3.  The schema for World is id (int, primary key) and randomNumber (int).
-
-4.  The request handler must retrieve a set of World objects, equal in count to the queries parameter, from the World database table.
-
-5.  Each row must be selected randomly in the same fashion as the single database query test (Test #2 above).
-
-6.  Since this test is designed to exercise multiple queries, each row must be selected individually by a query.
-	 It is not acceptable to retrieve all required rows using a SELECT ... WHERE id IN (...) clause.
-
-7.  Each World object must be added to a list or array.
-
-8.  The list or array must be serialized to JSON and sent as a response.
-
-9.  The response content type must be set to application/json.
-
-10. The response headers must include either Content-Length or Transfer-Encoding.
-
-11. The response headers must include Server and Date.
-
-12. Use of an in-memory cache of World objects or rows by the application is not permitted.
-
-13. Use of prepared statements for SQL database tests (e.g., for MySQL) is encouraged but not required.
-
-14. gzip compression is not permitted.
-
-15. Server support for HTTP Keep-Alive is strongly encouraged but not required.
-
-16. If HTTP Keep-Alive is enabled, no maximum Keep-Alive timeout is specified by this test.
-
-17. The request handler will be exercised at 256 concurrency only.
-
-18. The request handler will be exercised with query counts of 1, 5, 10, 15, and 20.
-
-19. The request handler will be exercised using GET requests.
-
-Example request:
-
-GET /queries?queries=10 HTTP/1.1
-Host: server
-User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00
-Cookie: uid=12345678901234567890; __utma=1.1234567890.1234567890.1234567890.1234567890.12; wd=2560x1600
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-US,en;q=0.5
-Connection: keep-alive
-
-Example response:
-
-HTTP/1.1 200 OK
-Content-Type: application/json; charset=UTF-8
-Content-Length: 315
-Server: Example
-Date: Wed, 17 Apr 2013 12:00:00 GMT
-
-[{"id":4174,"randomNumber":331},{"id":51,"randomNumber":6544},{"id":4462,"randomNumber":952},{"id":2221,"randomNumber":532},{"id":9276,"randomNumber":3097},{"id":3056,"randomNumber":7293},{"id":6964,"randomNumber":620},{"id":675,"randomNumber":6601},{"id":8414,"randomNumber":6569},{"id":2753,"randomNumber":4065}]
--->
-<!--#declaration
-#include "world.h"
-
-#define AS_cpoll_cppsp_DO
-
-#ifndef AS_cpoll_cppsp_DO
-static UValue*	pvalue;
-#endif
-static UOrmSession*		psql_queries;
-static UOrmStatement*	pstmt_queries;
-static World*				pworld_queries;
-static UVector<World*>* pvworld_queries;
-
-static void usp_init_queries()
-{
-	U_TRACE(5, "::usp_init_queries()")
-
-	psql_queries  = U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("hello_world")));
-	pstmt_queries = U_NEW(UOrmStatement(*psql_queries, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
-
-	if (pstmt_queries == 0) U_ERROR("usp_init_queries(): we cound't connect to db, exiting...");
-
-	pworld_queries  = U_NEW(World);
-	pvworld_queries = U_NEW(UVector<World*>(500));
-
-	pstmt_queries->use( pworld_queries->id);
-	pstmt_queries->into(pworld_queries->randomNumber);
-
-#ifndef AS_cpoll_cppsp_DO
-	pvalue = U_NEW(UValue(ARRAY_VALUE));
-#endif
-}
-
-static void usp_end_queries()
-{
-	U_TRACE(5, "::usp_end_queries()")
-
-	delete pstmt_queries;
-	delete psql_queries;
-	delete pvworld_queries;
-	delete pworld_queries;
-#ifndef AS_cpoll_cppsp_DO
-	delete pvalue;
-#endif
-}
--->
-<!--#args
-queries;
--->
-<!--#header
-Content-Type: application/json; charset=UTF-8
--->
-<!--#code
-int i = 0, num_queries = queries.strtol();
-
-	  if (num_queries <   1) num_queries = 1;
-else if (num_queries > 500) num_queries = 500;
-
-#ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR('[');
-#endif
-
-while (true)
-	{
-	pworld_queries->id = u_get_num_random(10000);
-
-	pstmt_queries->execute();
-
-#ifdef AS_cpoll_cppsp_DO
-	USP_PRINTF("{\"id\":%d,\"randomNumber\":%d}", pworld_queries->id, pworld_queries->randomNumber);
-#endif
-
-	pvworld_queries->push_back(U_NEW(World(*pworld_queries)));
-
-	if (++i == num_queries) break;
-
-#ifdef AS_cpoll_cppsp_DO
-	USP_PUTS_CHAR(',');
-#endif
-	}
-
-#ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR(']');
-#else
-USP_JSON_stringify(*pvalue, UVector<World*>, *pvworld_queries);
-#endif
-pvworld_queries->clear();
--->

+ 93 - 0
frameworks/C++/ULib/src/query.usp

@@ -0,0 +1,93 @@
+<!--#declaration
+#include "world.h"
+
+#define AS_cpoll_cppsp_DO
+
+#ifndef AS_cpoll_cppsp_DO
+static UValue* pvalue;
+#endif
+static UOrmSession*     psql_query;
+static UOrmStatement*   pstmt_query;
+static World*           pworld_query;
+static UVector<World*>* pvworld_query;
+
+static void usp_init_query()
+{
+   U_TRACE(5, "::usp_init_query()")
+
+   pworld_query  = U_NEW(World);
+   pvworld_query = U_NEW(UVector<World*>(500));
+
+#ifndef AS_cpoll_cppsp_DO
+   pvalue = U_NEW(UValue(ARRAY_VALUE));
+#endif
+}
+
+static void usp_fork_query()
+{
+   U_TRACE(5, "::usp_fork_query()")
+
+   psql_query  = U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("hello_world")));
+   pstmt_query = U_NEW(UOrmStatement(*psql_query, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
+
+   if (pstmt_queries == 0) U_ERROR("usp_fork_query(): we cound't connect to db, exiting...");
+
+   pstmt_query->use( pworld_query->id);
+   pstmt_query->into(pworld_query->randomNumber);
+}
+
+static void usp_end_query()
+{
+   U_TRACE(5, "::usp_end_query()")
+
+   delete pstmt_query;
+   delete psql_query;
+   delete pvworld_query;
+   delete pworld_query;
+#ifndef AS_cpoll_cppsp_DO
+   delete pvalue;
+#endif
+}
+-->
+<!--#args
+queries;
+-->
+<!--#header
+Content-Type: application/json; charset=UTF-8
+-->
+<!--#code
+int i = 0, num_queries = queries.strtol();
+
+     if (num_queries <   1) num_queries = 1;
+else if (num_queries > 500) num_queries = 500;
+
+#ifdef AS_cpoll_cppsp_DO
+USP_PUTS_CHAR('[');
+#endif
+
+while (true)
+   {
+   pworld_query->id = u_get_num_random(10000);
+
+   pstmt_query->execute();
+
+#ifdef AS_cpoll_cppsp_DO
+   USP_PRINTF("{\"id\":%d,\"randomNumber\":%d}", pworld_query->id, pworld_query->randomNumber);
+#endif
+
+   pvworld_query->push_back(U_NEW(World(*pworld_query)));
+
+   if (++i == num_query) break;
+
+#ifdef AS_cpoll_cppsp_DO
+   USP_PUTS_CHAR(',');
+#endif
+   }
+
+#ifdef AS_cpoll_cppsp_DO
+USP_PUTS_CHAR(']');
+#else
+USP_JSON_stringify(*pvalue, UVector<World*>, *pvworld_query);
+#endif
+pvworld_query->clear();
+-->

+ 109 - 0
frameworks/C++/ULib/src/update.usp

@@ -0,0 +1,109 @@
+<!--#declaration
+#include "world.h"
+
+#define AS_cpoll_cppsp_DO
+
+#ifndef AS_cpoll_cppsp_DO
+static UValue* pvalue;
+#endif
+static UOrmSession*     psql_update;
+static UOrmStatement*   pstmt1;
+static UOrmStatement*   pstmt2;
+static World*           pworld_update;
+static UVector<World*>* pvworld_update;
+
+static void usp_init_update()
+{
+   U_TRACE(5, "::usp_init_update()")
+
+   pworld_update  = U_NEW(World);
+   pvworld_update = U_NEW(UVector<World*>(500));
+
+#ifndef AS_cpoll_cppsp_DO
+   pvalue = U_NEW(UValue(ARRAY_VALUE));
+#endif
+}
+
+static void usp_fork_update()
+{
+   U_TRACE(5, "::usp_fork_update()")
+
+   psql_update = U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("hello_world")));
+
+   pstmt1 = U_NEW(UOrmStatement(*psql_update, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
+   pstmt2 = U_NEW(UOrmStatement(*psql_update, U_CONSTANT_TO_PARAM("UPDATE World SET randomNumber = ? WHERE id = ?")));
+
+   if (pstmt1 == 0 ||
+       pstmt2 == 0)
+      {
+      U_ERROR("usp_fork_update(): we cound't connect to db, exiting...");
+      }
+
+   pstmt1->use( pworld_update->id);
+   pstmt1->into(pworld_update->randomNumber);
+   pstmt2->use( pworld_update->randomNumber, pworld_update->id);
+}
+
+static void usp_end_update()
+{
+   U_TRACE(5, "::usp_end_update()")
+
+   delete pstmt1;
+   delete pstmt2;
+   delete psql_update;
+   delete pvworld_update;
+   delete pworld_update;
+#ifndef AS_cpoll_cppsp_DO
+   delete pvalue;
+#endif
+}
+-->
+<!--#args
+queries;
+-->
+<!--#header
+Content-Type: application/json; charset=UTF-8
+-->
+<!--#code
+int i = 0, num_queries = queries.strtol();
+
+     if (num_queries <   1) num_queries = 1;
+else if (num_queries > 500) num_queries = 500;
+
+#ifdef AS_cpoll_cppsp_DO
+USP_PUTS_CHAR('[');
+#endif
+
+while (true)
+   {
+   pworld_update->id = u_get_num_random(10000);
+
+   pstmt1->execute();
+
+   U_INTERNAL_DUMP("pworld_update->randomNumber = %d", pworld_update->randomNumber)
+
+   pworld_update->randomNumber = u_get_num_random(10000);
+
+   pstmt2->execute();
+
+#ifdef AS_cpoll_cppsp_DO
+   USP_PRINTF("{\"id\":%d,\"randomNumber\":%d}", pworld_update->id, pworld_update->randomNumber);
+#endif
+
+   pvworld_update->push_back(U_NEW(World(*pworld_update)));
+
+   if (++i == num_queries) break;
+
+#ifdef AS_cpoll_cppsp_DO
+   USP_PUTS_CHAR(',');
+#endif
+   }
+
+#ifdef AS_cpoll_cppsp_DO
+USP_PUTS_CHAR(']');
+#else
+USP_JSON_stringify(*pvalue, UVector<World*>, *pvworld_update);
+#endif
+
+pvworld_update->clear();
+-->

+ 0 - 184
frameworks/C++/ULib/src/updates.usp

@@ -1,184 +0,0 @@
-<!--#
-Test 5: Database updates
-
-This test is a variation of Test #3 that exercises the ORM's persistence of
-objects and the database driver's performance at running UPDATE statements or similar.
-
-Requirements
-
-1.  The recommended URI is /updates.
-
-2.  For every request, an integer query string parameter named queries must be retrieved from the request.
-    The parameter specifies the number of rows to fetch and update in preparing the HTTP response (see below).
-
-3.  The queries parameter must be bounded to between 1 and 500. If the parameter is missing, is not an integer,
-	 or is an integer less than 1, the value should be interpreted as 1; if greater than 500, the value should be interpreted as 500.
-
-3.  The schema for World is id (int, primary key) and randomNumber (int).
-
-4.  The request handler must retrieve a set of World objects, equal in count to the queries parameter, from the World database table.
-
-5.  Each row must be selected randomly in the same fashion as the single database query test (Test #2 above).
-
-6.  At least the randomNumber field must be read from the database result set.
-
-7.  Each World object must have its randomNumber field updated to a new random integer between 1 and 10000.
-
-8.  Each World object must be persisted to the database with its new randomNumber value.
-
-9.  Use of batch updates is acceptable but not required.
-
-10. Use of transactions is acceptable but not required.
-
-11. For raw tests (that is, tests without an ORM), each updated row must receive a unique new randomNumber value.
-    It is not acceptable to change the randomNumber value of all rows to the same random number using an UPDATE ... WHERE id IN (...) clause.
-
-12. Each World object must be added to a list or array.
-
-13. The list or array must be serialized to JSON and sent as a response.
-
-14. The response content type must be set to application/json.
-
-15. The response headers must include either Content-Length or Transfer-Encoding.
-
-16. The response headers must include Server and Date.
-
-17. Use of an in-memory cache of World objects or rows by the application is not permitted.
-
-18. Use of prepared statements for SQL database tests (e.g., for MySQL) is encouraged but not required.
-
-19. gzip compression is not permitted.
-
-20. Server support for HTTP Keep-Alive is strongly encouraged but not required.
-
-21. If HTTP Keep-Alive is enabled, no maximum Keep-Alive timeout is specified by this test.
-
-22. The request handler will be exercised at 256 concurrency only.
-
-23. The request handler will be exercised with query counts of 1, 5, 10, 15, and 20.
-
-24. The request handler will be exercised using GET requests.
-
-Example request:
-
-GET /updates?queries=10 HTTP/1.1
-Host: server
-User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00
-Cookie: uid=12345678901234567890; __utma=1.1234567890.1234567890.1234567890.1234567890.12; wd=2560x1600
-Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-Accept-Language: en-US,en;q=0.5
-Connection: keep-alive
-
-Example response:
-
-HTTP/1.1 200 OK
-Content-Type: application/json; charset=UTF-8
-Content-Length: 315
-Server: Example
-Date: Wed, 17 Apr 2013 12:00:00 GMT
-
-[{"id":4174,"randomNumber":331},{"id":51,"randomNumber":6544},{"id":4462,"randomNumber":952},{"id":2221,"randomNumber":532},{"id":9276,"randomNumber":3097},{"id":3056,"randomNumber":7293},{"id":6964,"randomNumber":620},{"id":675,"randomNumber":6601},{"id":8414,"randomNumber":6569},{"id":2753,"randomNumber":4065}]
--->
-<!--#declaration
-#include "world.h"
-
-#define AS_cpoll_cppsp_DO
-
-#ifndef AS_cpoll_cppsp_DO
-static UValue*	pvalue;
-#endif
-static UOrmSession*		psql_updates;
-static UOrmStatement*	pstmt1;
-static UOrmStatement*	pstmt2;
-static World*				pworld_updates;
-static UVector<World*>* pvworld_updates;
-
-static void usp_init_updates()
-{
-	U_TRACE(5, "::usp_init_updates()")
-
-	psql_updates = U_NEW(UOrmSession(U_CONSTANT_TO_PARAM("hello_world")));
-	pstmt1		 = U_NEW(UOrmStatement(*psql_updates, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
-	pstmt2		 = U_NEW(UOrmStatement(*psql_updates, U_CONSTANT_TO_PARAM("UPDATE World SET randomNumber = ? WHERE id = ?")));
-
-	if (pstmt1 == 0 ||
-		 pstmt2 == 0)
-		{
-		U_ERROR("usp_init_updates(): we cound't connect to db, exiting...");
-		}
-
-	pworld_updates  = U_NEW(World);
-	pvworld_updates = U_NEW(UVector<World*>(500));
-
-	pstmt1->use( pworld_updates->id);
-	pstmt1->into(pworld_updates->randomNumber);
-	pstmt2->use( pworld_updates->randomNumber, pworld_updates->id);
-
-#ifndef AS_cpoll_cppsp_DO
-	pvalue = U_NEW(UValue(ARRAY_VALUE));
-#endif
-}
-
-static void usp_end_updates()
-{
-	U_TRACE(5, "::usp_end_updates()")
-
-	delete pstmt1;
-	delete pstmt2;
-	delete psql_updates;
-	delete pvworld_updates;
-	delete pworld_updates;
-#ifndef AS_cpoll_cppsp_DO
-	delete pvalue;
-#endif
-}
--->
-<!--#args
-queries;
--->
-<!--#header
-Content-Type: application/json; charset=UTF-8
--->
-<!--#code
-int i = 0, num_queries = queries.strtol();
-
-	  if (num_queries <   1) num_queries = 1;
-else if (num_queries > 500) num_queries = 500;
-
-#ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR('[');
-#endif
-
-while (true)
-	{
-	pworld_updates->id = u_get_num_random(10000);
-
-	pstmt1->execute();
-
-	U_INTERNAL_DUMP("pworld_updates->randomNumber = %d", pworld_updates->randomNumber)
-
-	pworld_updates->randomNumber = u_get_num_random(10000);
-
-	pstmt2->execute();
-
-#ifdef AS_cpoll_cppsp_DO
-	USP_PRINTF("{\"id\":%d,\"randomNumber\":%d}", pworld_updates->id, pworld_updates->randomNumber);
-#endif
-
-	pvworld_updates->push_back(U_NEW(World(*pworld_updates)));
-
-	if (++i == num_queries) break;
-
-#ifdef AS_cpoll_cppsp_DO
-	USP_PUTS_CHAR(',');
-#endif
-	}
-
-#ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR(']');
-#else
-USP_JSON_stringify(*pvalue, UVector<World*>, *pvworld_updates);
-#endif
-
-pvworld_updates->clear();
--->

+ 58 - 58
frameworks/C++/ULib/src/world.h

@@ -8,99 +8,99 @@
 
 
 class World {
 class World {
 public:
 public:
-	// Check for memory error
-	U_MEMORY_TEST
+   // Check for memory error
+   U_MEMORY_TEST
 
 
-	// Allocator e Deallocator
-	U_MEMORY_ALLOCATOR
-	U_MEMORY_DEALLOCATOR
+   // Allocator e Deallocator
+   U_MEMORY_ALLOCATOR
+   U_MEMORY_DEALLOCATOR
 
 
-	int id, randomNumber;
+   int id, randomNumber;
 
 
-	// CONSTRUCTOR
+   // CONSTRUCTOR
 
 
-	World()
-		{
-		U_TRACE_REGISTER_OBJECT(5, World, "")
-		}
+   World()
+      {
+      U_TRACE_REGISTER_OBJECT(5, World, "")
+      }
 
 
-	World(const World& w) : id(w.id), randomNumber(w.randomNumber)
-		{
-		U_TRACE_REGISTER_OBJECT(5, World, "%p", &w)
+   World(const World& w) : id(w.id), randomNumber(w.randomNumber)
+      {
+      U_TRACE_REGISTER_OBJECT(5, World, "%p", &w)
 
 
-		U_MEMORY_TEST_COPY(w)
-		}
+      U_MEMORY_TEST_COPY(w)
+      }
 
 
-	~World()
-		{
-		U_TRACE_UNREGISTER_OBJECT(5, World)
-		}
+   ~World()
+      {
+      U_TRACE_UNREGISTER_OBJECT(5, World)
+      }
 
 
 #ifdef DEBUG
 #ifdef DEBUG
-	const char* dump(bool breset) const
-		{
-		*UObjectIO::os << "id           " << id				<< '\n'
-							<< "randomNumber " << randomNumber;
+   const char* dump(bool breset) const
+      {
+      *UObjectIO::os << "id           " << id            << '\n'
+                     << "randomNumber " << randomNumber;
 
 
-		if (breset)
-			{
-			UObjectIO::output();
+      if (breset)
+         {
+         UObjectIO::output();
 
 
-			return UObjectIO::buffer_output;
-			}
+         return UObjectIO::buffer_output;
+         }
 
 
-		return 0;
-		}
+      return 0;
+      }
 #endif
 #endif
 
 
 private:
 private:
-	World& operator=(const World&) { return *this; }
+   World& operator=(const World&) { return *this; }
 };
 };
 
 
 // ORM TEMPLATE SPECIALIZATIONS
 // ORM TEMPLATE SPECIALIZATIONS
 
 
 template <> class U_EXPORT UOrmTypeHandler<World> : public UOrmTypeHandler_Base {
 template <> class U_EXPORT UOrmTypeHandler<World> : public UOrmTypeHandler_Base {
 public:
 public:
-	explicit UOrmTypeHandler(World& val) : UOrmTypeHandler_Base(&val) {}
+   explicit UOrmTypeHandler(World& val) : UOrmTypeHandler_Base(&val) {}
 
 
-	void bindParam(UOrmStatement* stmt) const
-		{
-		U_TRACE(0, "UOrmTypeHandler<World>::bindParam(%p)", stmt)
+   void bindParam(UOrmStatement* stmt) const
+      {
+      U_TRACE(0, "UOrmTypeHandler<World>::bindParam(%p)", stmt)
 
 
-		stmt->bindParam(U_ORM_TYPE_HANDLER(World, id,				int));
-		stmt->bindParam(U_ORM_TYPE_HANDLER(World, randomNumber,	int));
-		}
+      stmt->bindParam(U_ORM_TYPE_HANDLER(World, id,            int));
+      stmt->bindParam(U_ORM_TYPE_HANDLER(World, randomNumber,  int));
+      }
 
 
-	void bindResult(UOrmStatement* stmt)
-		{
-		U_TRACE(0, "UOrmTypeHandler<World>::bindResult(%p)", stmt)
+   void bindResult(UOrmStatement* stmt)
+      {
+      U_TRACE(0, "UOrmTypeHandler<World>::bindResult(%p)", stmt)
 
 
-		stmt->bindResult(U_ORM_TYPE_HANDLER(World, id,				int));
-		stmt->bindResult(U_ORM_TYPE_HANDLER(World, randomNumber,	int));
-		}
+      stmt->bindResult(U_ORM_TYPE_HANDLER(World, id,           int));
+      stmt->bindResult(U_ORM_TYPE_HANDLER(World, randomNumber, int));
+      }
 };
 };
 
 
 // JSON TEMPLATE SPECIALIZATIONS
 // JSON TEMPLATE SPECIALIZATIONS
 
 
 template <> class U_EXPORT UJsonTypeHandler<World> : public UJsonTypeHandler_Base {
 template <> class U_EXPORT UJsonTypeHandler<World> : public UJsonTypeHandler_Base {
 public:
 public:
-	explicit UJsonTypeHandler(World& val) : UJsonTypeHandler_Base(&val) {}
+   explicit UJsonTypeHandler(World& val) : UJsonTypeHandler_Base(&val) {}
 
 
-	void toJSON(UValue& json)
-		{
-		U_TRACE(0, "UJsonTypeHandler<World>::toJSON(%p)", &json)
+   void toJSON(UValue& json)
+      {
+      U_TRACE(0, "UJsonTypeHandler<World>::toJSON(%p)", &json)
 
 
-		json.toJSON(U_JSON_TYPE_HANDLER(World, id,				int));
-		json.toJSON(U_JSON_TYPE_HANDLER(World, randomNumber,	int));
-		}
+      json.toJSON(U_JSON_TYPE_HANDLER(World, id,            int));
+      json.toJSON(U_JSON_TYPE_HANDLER(World, randomNumber,  int));
+      }
 
 
-	void fromJSON(UValue& json)
-		{
-		U_TRACE(0, "UJsonTypeHandler<World>::fromJSON(%p)", &json)
+   void fromJSON(UValue& json)
+      {
+      U_TRACE(0, "UJsonTypeHandler<World>::fromJSON(%p)", &json)
 
 
-		json.fromJSON(U_JSON_TYPE_HANDLER(World, id,				 int));
-		json.fromJSON(U_JSON_TYPE_HANDLER(World, randomNumber, int));
-		}
+      json.fromJSON(U_JSON_TYPE_HANDLER(World, id,           int));
+      json.fromJSON(U_JSON_TYPE_HANDLER(World, randomNumber, int));
+      }
 };
 };
 
 
 #endif
 #endif