ソースを参照

ULib: code update (#2881)

* ULib: code update

* ULib: code update

* ULib: code update

* ULib: code update

* ULib: code update

* ULib: code update

* ULib: code update
stefano casazza 8 年 前
コミット
90ba606ca9

+ 2 - 2
frameworks/C++/ulib/setup_mysql.sh

@@ -4,7 +4,7 @@ fw_depends mysql ulib
 
 # Travis is broken
 if [ "$TRAVIS" != "true" ]; then
-MAX_THREADS=$(( 3 * $CPU_COUNT / 2 ))
+MAX_THREADS=$CPU_COUNT
 else
 MAX_THREADS=$(( 2 * $CPU_COUNT ))
 fi
@@ -17,7 +17,7 @@ sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 100|g" $IROOT
 
 # 2. Start ULib Server (userver_tcp)
 export ORM_DRIVER="mysql"
-export UMEMPOOL="545,0,0,49,275,-14,-13,-25,41"
+export UMEMPOOL="750,0,123,251,305,53,-6,-26,52"
 export ORM_OPTION="host=${DBHOST} user=benchmarkdbuser password=benchmarkdbpass character-set=utf8 dbname=hello_world"
 
 # Never use setcap inside of TRAVIS 

+ 1 - 1
frameworks/C++/ulib/setup_postgres.sh

@@ -12,7 +12,7 @@ sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 100|g" $IROOT
 
 # 2. Start ULib Server (userver_tcp)
 export ORM_DRIVER="pgsql"
-export UMEMPOOL="545,0,0,41,275,-14,-13,-25,41"
+export UMEMPOOL="750,0,123,251,305,53,-6,-26,52"
 export ORM_OPTION="host=${DBHOST} user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world client_encoding=UTF8"
 
 # Never use setcap inside of TRAVIS 

+ 1 - 1
frameworks/C++/ulib/setup_sqlite.sh

@@ -17,7 +17,7 @@ sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 100|g" $IROOT
 
 # 2. Start ULib Server (userver_tcp)
 export ORM_DRIVER="sqlite"
-export UMEMPOOL="545,0,0,49,275,-14,-13,-25,41"
+export UMEMPOOL="750,0,123,251,305,53,-6,-26,52"
 export ORM_OPTION="host=${DBHOST} user=benchmarkdbuser password=benchmarkdbpass character-set=utf8 dbname=${IROOT}/ULib/db/%.*s"
 
 # Never use setcap inside of TRAVIS 

+ 62 - 44
frameworks/C++/ulib/src/fortune.usp

@@ -5,90 +5,108 @@ TechEmpower Web Framework Benchmarks
 <!--#declaration
 #include "fortune.h"
 
-static Fortune*           pfortune;
+static Fortune*			  pfortune;
 static Fortune*           pfortune2add;
 static UString*           pencoded;
-static UOrmSession*       psql_fortune;
-static UOrmStatement*     pstmt_fortune;
+static UOrmSession*		  psql_fortune;
+static UOrmStatement*	  pstmt_fortune;
 static UVector<Fortune*>* pvfortune;
 
 static void usp_fork_fortune()
 {
-   U_TRACE(5, "::usp_fork_fortune()")
+	U_TRACE(5, "::usp_fork_fortune()")
 
-   U_NEW(UOrmSession, psql_fortune, UOrmSession(U_CONSTANT_TO_PARAM("fortune")));
+	U_NEW(UOrmSession, psql_fortune, UOrmSession(U_CONSTANT_TO_PARAM("fortune")));
 
-   U_INTERNAL_DUMP("psql_fortune = %p", psql_fortune)
+	U_INTERNAL_DUMP("psql_fortune = %p", psql_fortune)
 
-   if (psql_fortune->isReady() == false)
-      {
-      U_WARNING("usp_fork_fortune(): we cound't connect to db");
+	if (psql_fortune->isReady() == false)
+		{
+		U_WARNING("usp_fork_fortune(): we cound't connect to db");
 
-      return;
-      }
+		return;
+		}
 
-   U_NEW(UOrmStatement, pstmt_fortune, UOrmStatement(*psql_fortune, U_CONSTANT_TO_PARAM("SELECT id, message FROM Fortune")));
+	U_NEW(UOrmStatement, pstmt_fortune, UOrmStatement(*psql_fortune, U_CONSTANT_TO_PARAM("SELECT id, message FROM Fortune")));
 
-   if (UOrmDriver::isPGSQL()) *psql_fortune << "BEGIN ISOLATION LEVEL SERIALIZABLE; COMMIT";
+//	if (UOrmDriver::isPGSQL()) *psql_fortune << "BEGIN ISOLATION LEVEL SERIALIZABLE; COMMIT";
 
-   U_NEW(Fortune, pfortune, Fortune);
+	U_NEW(Fortune, pfortune, Fortune);
 
-   pstmt_fortune->into(*pfortune);
+	pstmt_fortune->into(*pfortune);
 
-   U_NEW(UString, pencoded, UString(100U));
-   U_NEW(UVector<Fortune*>, pvfortune, UVector<Fortune*>);
-   U_NEW(Fortune, pfortune2add, Fortune(0, U_STRING_FROM_CONSTANT("Additional fortune added at request time.")));
+	U_NEW(UString, pencoded, UString(100U));
+	U_NEW(UVector<Fortune*>, pvfortune, UVector<Fortune*>);
+	U_NEW(Fortune, pfortune2add, Fortune(0, U_STRING_FROM_CONSTANT("Additional fortune added at request time.")));
 }
 
 #ifdef DEBUG
 static void usp_end_fortune()
 {
-   U_TRACE(5, "::usp_end_fortune()")
+	U_TRACE(5, "::usp_end_fortune()")
 
-   U_INTERNAL_DUMP("psql_fortune = %p", psql_fortune)
+	U_INTERNAL_DUMP("psql_fortune = %p", psql_fortune)
 
-   delete psql_fortune;
+	delete psql_fortune;
 
-   if (pstmt_fortune)
-      {
-      delete pstmt_fortune;
-      delete pfortune;
-      delete pencoded;
-      delete pvfortune;
-      delete pfortune2add;
-      }
+	if (pstmt_fortune)
+		{
+		delete pstmt_fortune;
+		delete pfortune;
+		delete pencoded;
+		delete pvfortune;
+		delete pfortune2add;
+		}
 }
 #endif
 -->
 <!doctype html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><!--#code
+uint32_t sz;
 Fortune* item;
+char* s   = UClientImage_Base::wbuffer->data();
+char* ptr = UClientImage_Base::wbuffer->pend();
 
 U_NEW(Fortune, item, Fortune(*pfortune2add));
+
 pvfortune->push_back(item);
 
 pstmt_fortune->execute();
 
-do {
-   U_NEW(Fortune, item, Fortune(*pfortune));
+do	{
+	U_NEW(Fortune, item, Fortune(*pfortune));
+
    pvfortune->push_back(item);
-   }
+	}
 while (pstmt_fortune->nextRow());
 
 pvfortune->sort(Fortune::cmp_obj);
 
 for (uint32_t i = 0, n = pvfortune->size(); i < n; ++i)
-   {
-   Fortune* elem = (*pvfortune)[i];
-
-   UXMLEscape::encode(elem->message, *pencoded);
-
-   USP_PRINTF_ADD(
-      "<tr>"
-      "<td>%u</td>"
-      "<td>%v</td>"
-      "</tr>",
-      elem->id, pencoded->rep);
-   }
+	{
+	Fortune* elem = (*pvfortune)[i];
+
+	UXMLEscape::encode(elem->message, *pencoded);
+
+	sz = pencoded->size();
+
+	u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','t','r','>','<','t','d','>'));
+
+	ptr = u_num2str32(elem->id, ptr+8);
+
+	u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','/','t','d','>','<','t','d'));
+							 ptr += 8;
+
+	*ptr++ = '>';
+
+	(void) memcpy(ptr, pencoded->data(), sz);
+					  ptr +=					    sz;
+
+	u_put_unalignedp64(ptr,   U_MULTICHAR_CONSTANT64('<','/','t','d','>','<','/','t'));
+	u_put_unalignedp16(ptr+8, U_MULTICHAR_CONSTANT16('r','>'));
+							 ptr += 10;
+	}
+
+UClientImage_Base::wbuffer->size_adjust(ptr - s);
 
 pvfortune->clear();
 --></table></body></html>

+ 25 - 2
frameworks/C++/ulib/src/mdb.usp

@@ -5,6 +5,7 @@ TechEmpower Web Framework Benchmarks
 <!--#declaration
 #include "world.h"
 
+static bson_t* query;  
 static UMongoDBClient* mc;
 
 static void usp_fork_mdb()
@@ -26,6 +27,8 @@ static void usp_fork_mdb()
 
       return;
       }
+
+   query = (bson_t*) U_SYSCALL_NO_PARAM(bson_new);  
 }
 
 #ifdef DEBUG
@@ -34,6 +37,8 @@ static void usp_end_mdb()
    U_TRACE(5, "::usp_end_mdb()")
 
    delete mc;
+
+   if (query) U_SYSCALL_VOID(bson_destroy, "%p", query);
 }
 #endif
 -->
@@ -44,12 +49,30 @@ Content-Type: application/json
 uint32_t id;
 UString result;
 
-(void) mc->findOne(id = u_get_num_random(10000-1));
+(void) mc->findOne(id = u_get_num_random(10000-1), query);
 
 (void) U_JFIND(mc->vitem[0], "randomNumber", result);
 
 #ifdef AS_cpoll_cppsp_DO
-USP_PRINTF_ADD("{\"id\":%u,\"randomNumber\":%v}", id, result.rep);
+char* s     = UClientImage_Base::wbuffer->data();
+char* ptr   = UClientImage_Base::wbuffer->pend();
+uint32_t sz = result.size();
+
+u_put_unalignedp32(ptr,   U_MULTICHAR_CONSTANT32('{','"','i','d'));
+u_put_unalignedp16(ptr+4, U_MULTICHAR_CONSTANT16('"',':'));
+
+ptr = u_num2str32(id, ptr+6);
+
+u_put_unalignedp64(ptr,   U_MULTICHAR_CONSTANT64(',','"','r','a','n','d','o','m'));
+u_put_unalignedp64(ptr+8, U_MULTICHAR_CONSTANT64('N','u','m','b','e','r','"',':'));
+                   ptr += 16;
+
+(void) memcpy(ptr, result.data(), sz);
+              ptr +=              sz;
+
+*ptr++ = '}';
+
+UClientImage_Base::wbuffer->size_adjust(ptr - s);
 #else
 World world(id, result.strtoul());
 USP_OBJ_JSON_stringify(world);

+ 24 - 9
frameworks/C++/ulib/src/mfortune.usp

@@ -53,8 +53,10 @@ static void usp_end_mfortune()
 -->
 <!doctype html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><!--#code
 Fortune* item;
-uint32_t i, n;
 UString result;
+uint32_t i, n, sz;
+char* s   = UClientImage_Base::wbuffer->data();
+char* ptr = UClientImage_Base::wbuffer->pend();
 
 U_NEW(Fortune, item, Fortune(*pfortune2add));
 
@@ -64,12 +66,12 @@ pvfortune->push_back(item);
 
 for (i = 0, n = mc->vitem.size(); i < n; ++i)
    {
-   result.clear();
-
    (void) U_JFIND(mc->vitem[i], "message", result);
 
    U_NEW(Fortune, item, Fortune(i+1, result));
 
+   result.clear();
+
    pvfortune->push_back(item);
    }
 
@@ -81,13 +83,26 @@ for (i = 0, ++n; i < n; ++i)
 
    UXMLEscape::encode(elem->message, *pencoded);
 
-   USP_PRINTF_ADD(
-      "<tr>"
-      "<td>%u</td>"
-      "<td>%v</td>"
-      "</tr>",
-      elem->id, pencoded->rep);
+   sz = pencoded->size();
+
+   u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','t','r','>','<','t','d','>'));
+
+   ptr = u_num2str32(elem->id, ptr+8);
+
+   u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','/','t','d','>','<','t','d'));
+                      ptr += 8;
+
+   *ptr++ = '>';
+
+   (void) memcpy(ptr, pencoded->data(), sz);
+                 ptr +=                 sz;
+
+   u_put_unalignedp64(ptr,   U_MULTICHAR_CONSTANT64('<','/','t','d','>','<','/','t'));
+   u_put_unalignedp16(ptr+8, U_MULTICHAR_CONSTANT16('r','>'));
+                      ptr += 10;
    }
 
+UClientImage_Base::wbuffer->size_adjust(ptr - s);
+
 pvfortune->clear();
 --></table></body></html>

+ 33 - 7
frameworks/C++/ulib/src/mquery.usp

@@ -5,6 +5,7 @@ TechEmpower Web Framework Benchmarks
 <!--#declaration
 #include "world.h"
 
+static bson_t* query;  
 static UMongoDBClient* mc;
 
 #ifndef AS_cpoll_cppsp_DO
@@ -31,6 +32,8 @@ static void usp_fork_mquery()
       return;
       }
 
+   query = (bson_t*) U_SYSCALL_NO_PARAM(bson_new);  
+
 #ifndef AS_cpoll_cppsp_DO
    U_NEW(UVector<World*>, pvworld_query, UVector<World*>(500));
 #endif
@@ -43,6 +46,8 @@ static void usp_end_mquery()
 
    delete mc;
 
+   if (query) U_SYSCALL_VOID(bson_destroy, "%p", query);
+
 #ifndef AS_cpoll_cppsp_DO
    if (pvworld_query) delete pvworld_query;
 #endif
@@ -58,19 +63,36 @@ UString rnumber;
 int i = 0, num_queries = UHTTP::getFormFirstNumericValue(1, 500);
 
 #ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR('[');
+(void) UClientImage_Base::wbuffer->reserve(36U * num_queries);
+
+char* s   = UClientImage_Base::wbuffer->data();
+char* ptr = UClientImage_Base::wbuffer->pend();
+
+*ptr++ = '[';
 #endif
 
 while (true)
    {
-   (void) mc->findOne(id = u_get_num_random(10000-1));
-
-   rnumber.clear();
+   (void) mc->findOne(id = u_get_num_random(10000-1), query);
 
    (void) U_JFIND(mc->vitem[0], "randomNumber", rnumber);
 
 #ifdef AS_cpoll_cppsp_DO
-   USP_PRINTF("{\"id\":%u,\"randomNumber\":%v}", id, rnumber.rep);
+   uint32_t sz = rnumber.size();
+
+   u_put_unalignedp32(ptr,   U_MULTICHAR_CONSTANT32('{','"','i','d'));
+   u_put_unalignedp16(ptr+4, U_MULTICHAR_CONSTANT16('"',':'));
+
+   ptr = u_num2str32(id, ptr+6);
+
+   u_put_unalignedp64(ptr,   U_MULTICHAR_CONSTANT64(',','"','r','a','n','d','o','m'));
+   u_put_unalignedp64(ptr+8, U_MULTICHAR_CONSTANT64('N','u','m','b','e','r','"',':'));
+                      ptr += 16;
+
+   (void) memcpy(ptr, rnumber.data(), sz);
+                 ptr +=               sz;
+
+   *ptr++ = '}';
 #else
    World* pworld;
 
@@ -79,15 +101,19 @@ while (true)
    pvworld_query->push_back(pworld);
 #endif
 
+   rnumber.clear();
+
    if (++i == num_queries) break;
 
 #ifdef AS_cpoll_cppsp_DO
-   USP_PUTS_CHAR(',');
+   *ptr++ = ',';
 #endif
    }
 
 #ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR(']');
+*ptr++ = ']';
+
+UClientImage_Base::wbuffer->size_adjust(ptr - s);
 #else
 USP_OBJ_JSON_stringify(*pvworld_query);
 pvworld_query->clear();

+ 27 - 5
frameworks/C++/ulib/src/mupdate.usp

@@ -5,6 +5,7 @@ TechEmpower Web Framework Benchmarks
 <!--#declaration
 #include "world.h"
 
+static bson_t* query;  
 static UMongoDBClient* mc;
 
 #ifndef AS_cpoll_cppsp_DO
@@ -31,6 +32,8 @@ static void usp_fork_mupdate()
       return;
       }
 
+   query = (bson_t*) U_SYSCALL_NO_PARAM(bson_new);  
+
 #ifndef AS_cpoll_cppsp_DO
    U_NEW(UVector<World*>, pvworld_update, UVector<World*>(500));
 #endif
@@ -43,6 +46,8 @@ static void usp_end_mupdate()
 
    delete mc;
 
+   if (query) U_SYSCALL_VOID(bson_destroy, "%p", query);
+
 #ifndef AS_cpoll_cppsp_DO
    if (pvworld_update) delete pvworld_update;
 #endif
@@ -58,18 +63,33 @@ uint32_t id, rnum;
 int i = 0, num_queries = UHTTP::getFormFirstNumericValue(1, 500);
 
 #ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR('[');
+(void) UClientImage_Base::wbuffer->reserve(36U * num_queries);
+
+char* s   = UClientImage_Base::wbuffer->data();
+char* ptr = UClientImage_Base::wbuffer->pend();
+
+*ptr++ = '[';
 #endif
 
 while (true)
    {
 // mc->updateOneBulk(bulk, id = u_get_num_random(10000-1), "randomNumber", rnum = u_get_num_random(10000-1));
 
-   if (mc->findOne(id = u_get_num_random(10000-1)) &&
+   if (mc->findOne(id = u_get_num_random(10000-1), query) &&
        mc->update( id, "randomNumber", rnum = u_get_num_random(10000-1)))
       {
 #  ifdef AS_cpoll_cppsp_DO
-      USP_PRINTF("{\"id\":%u,\"randomNumber\":%u}", id, rnum);
+      u_put_unalignedp32(ptr,   U_MULTICHAR_CONSTANT32('{','"','i','d'));
+      u_put_unalignedp16(ptr+4, U_MULTICHAR_CONSTANT16('"',':'));
+
+      ptr = u_num2str32(id, ptr+6);
+
+      u_put_unalignedp64(ptr,   U_MULTICHAR_CONSTANT64(',','"','r','a','n','d','o','m'));
+      u_put_unalignedp64(ptr+8, U_MULTICHAR_CONSTANT64('N','u','m','b','e','r','"',':'));
+
+      ptr = u_num2str32(rnum, ptr+16);
+
+      *ptr++ = '}';
 #  else
       World* pworld;
 
@@ -82,14 +102,16 @@ while (true)
    if (++i == num_queries) break;
 
 #ifdef AS_cpoll_cppsp_DO
-   USP_PUTS_CHAR(',');
+   *ptr++ = ',';
 #endif
    }
 
 // (void) mc->executeBulk(bulk);
 
 #ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR(']');
+*ptr++ = ']';
+
+UClientImage_Base::wbuffer->size_adjust(ptr - s);
 #else
 USP_OBJ_JSON_stringify(*pvworld_update);
 pvworld_update->clear();

+ 1 - 1
frameworks/C++/ulib/src/query.usp

@@ -28,7 +28,7 @@ static void usp_fork_query()
 
    U_NEW(UOrmStatement, pstmt_query, UOrmStatement(*psql_query, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
 
-   if (UOrmDriver::isPGSQL()) *psql_query << "BEGIN TRANSACTION";
+// if (UOrmDriver::isPGSQL()) *psql_query << "BEGIN TRANSACTION";
 
    U_NEW(World, pworld_query, World);
 

+ 92 - 37
frameworks/C++/ulib/src/update.usp

@@ -5,14 +5,12 @@ TechEmpower Web Framework Benchmarks
 <!--#declaration
 #include "world.h"
 
-static World*         pworld_update;
-static UOrmSession*   psql_update;
-static UOrmStatement* pstmt1;
-static UOrmStatement* pstmt2;
-
-#ifndef AS_cpoll_cppsp_DO
+static bool             bpgsql;
+static World*           pworld_update;
+static UOrmSession*     psql_update;
+static UOrmStatement*   pstmt;
+static UOrmStatement*   pstmt1;
 static UVector<World*>* pvworld_update;
-#endif
 
 static void usp_fork_update()
 {
@@ -27,20 +25,21 @@ static void usp_fork_update()
       return;
       }
 
-   U_NEW(UOrmStatement, pstmt1, UOrmStatement(*psql_update, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
-   U_NEW(UOrmStatement, pstmt2, UOrmStatement(*psql_update, U_CONSTANT_TO_PARAM("UPDATE World SET randomNumber = ? WHERE id = ?")));
+   U_NEW(World,           pworld_update,  World);
+   U_NEW(UVector<World*>, pvworld_update, UVector<World*>(500));
 
-   if (UOrmDriver::isPGSQL()) *psql_update << "SET synchronous_commit TO OFF";
+   U_NEW(UOrmStatement, pstmt, UOrmStatement(*psql_update, U_CONSTANT_TO_PARAM("SELECT randomNumber FROM World WHERE id = ?")));
 
-   U_NEW(World, pworld_update, World);
+   pstmt->use( pworld_update->id);
+   pstmt->into(pworld_update->randomNumber);
 
-   pstmt1->use( pworld_update->id);
-   pstmt1->into(pworld_update->randomNumber);
-   pstmt2->use( pworld_update->randomNumber, pworld_update->id);
+   if ((bpgsql = UOrmDriver::isPGSQL()) == false)
+      {
+      U_NEW(UOrmStatement, pstmt1, UOrmStatement(*psql_update, U_CONSTANT_TO_PARAM("UPDATE World SET randomNumber = ? WHERE id = ?")));
 
-#ifndef AS_cpoll_cppsp_DO
-   U_NEW(UVector<World*>, pvworld_update, UVector<World*>(500));
-#endif
+      pstmt1->use(pworld_update->randomNumber, pworld_update->id);
+      }
+// else *psql_update << "SET synchronous_commit TO OFF";
 }
 
 #ifdef DEBUG
@@ -50,16 +49,13 @@ static void usp_end_update()
 
    delete psql_update;
 
-   if (pstmt1 &&
-       pstmt2)
+   if (pstmt)
       {
-      delete pstmt1;
-      delete pstmt2;
+      delete pstmt;
       delete pworld_update;
-
-#  ifndef AS_cpoll_cppsp_DO
       delete pvworld_update;
-#  endif
+
+      if (bpgsql == false) delete pstmt1;
       }
 }
 #endif
@@ -68,43 +64,102 @@ static void usp_end_update()
 Content-Type: application/json
 -->
 <!--#code
+char* ptr;
+World* pworld;
+char query[8192];
 int i = 0, num_queries = UHTTP::getFormFirstNumericValue(1, 500);
 
-#ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR('[');
-#endif
+if (bpgsql)
+   {
+   (void) memcpy(query,          "UPDATE World SET randomNumber = v.randomNumber FROM (VALUES",
+                 U_CONSTANT_SIZE("UPDATE World SET randomNumber = v.randomNumber FROM (VALUES"));
+   ptr = query + U_CONSTANT_SIZE("UPDATE World SET randomNumber = v.randomNumber FROM (VALUES");
+   }
 
 while (true)
    {
    pworld_update->id = u_get_num_random(10000-1);
 
-   pstmt1->execute();
+   pstmt->execute();
 
    pworld_update->randomNumber = u_get_num_random(10000-1);
 
-   pstmt2->execute();
-
-#ifdef AS_cpoll_cppsp_DO
-   USP_PRINTF("{\"id\":%u,\"randomNumber\":%u}", pworld_update->id, pworld_update->randomNumber);
-#else
-   World* pworld;
+   if (bpgsql == false) pstmt1->execute();
 
    U_NEW(World, pworld, World(*pworld_update));
 
    pvworld_update->push_back(pworld);
+
+   if (++i == num_queries) break;
+   }
+
+#ifdef AS_cpoll_cppsp_DO
+(void) UClientImage_Base::wbuffer->reserve(36U * num_queries);
+
+char* s = UClientImage_Base::wbuffer->data();
+char* p = UClientImage_Base::wbuffer->pend();
+
+*p++ = '[';
+#endif
+
+if (bpgsql) pvworld_update->sort(World::cmp_obj);
+
+i = 0;
+
+while (true)
+   {
+   if (bpgsql)
+      {
+      pworld = pvworld_update->at(i);
+
+      *ptr++ = '(';
+
+      ptr = u_num2str32(pworld->id, ptr);
+
+      *ptr++ = ',';
+
+      ptr = u_num2str32(pworld->randomNumber, ptr);
+
+      u_put_unalignedp16(ptr, U_MULTICHAR_CONSTANT16(')',','));
+                         ptr += 2;
+      }
+
+#ifdef AS_cpoll_cppsp_DO
+   u_put_unalignedp32(p,   U_MULTICHAR_CONSTANT32('{','"','i','d'));
+   u_put_unalignedp16(p+4, U_MULTICHAR_CONSTANT16('"',':'));
+
+   p = u_num2str32(pworld->id, p+6);
+
+   u_put_unalignedp64(p,   U_MULTICHAR_CONSTANT64(',','"','r','a','n','d','o','m'));
+   u_put_unalignedp64(p+8, U_MULTICHAR_CONSTANT64('N','u','m','b','e','r','"',':'));
+
+   p = u_num2str32(pworld->randomNumber, p+16);
+
+   *p++ = '}';
 #endif
 
    if (++i == num_queries) break;
 
 #ifdef AS_cpoll_cppsp_DO
-   USP_PUTS_CHAR(',');
+   *p++ = ',';
 #endif
    }
 
 #ifdef AS_cpoll_cppsp_DO
-USP_PUTS_CHAR(']');
+*p++ = ']';
+
+UClientImage_Base::wbuffer->size_adjust(p - s);
 #else
 USP_OBJ_JSON_stringify(*pvworld_update);
-pvworld_update->clear();
 #endif
+
+pvworld_update->clear();
+
+if (bpgsql)
+   {
+   (void) memcpy(ptr-1,                 ") AS v (id,randomNumber) WHERE World.id = v.id;",
+                        U_CONSTANT_SIZE(") AS v (id,randomNumber) WHERE World.id = v.id;")+1);
+
+   if (psql_update->query(query, ptr + U_CONSTANT_SIZE(") AS v (id,randomNumber) WHERE World.id = v.id;") - query) == false) UHTTP::setInternalError(); 
+   }
 -->

+ 31 - 0
frameworks/C++/ulib/src/world.h

@@ -32,6 +32,13 @@ public:
       U_TRACE_REGISTER_OBJECT(5, World, "%u,%u", _id, _randomNumber)
       }
 
+   World(const World& w) : id(w.id), randomNumber(w.randomNumber)
+      {
+      U_TRACE_REGISTER_OBJECT(5, World, "%p", &w)
+
+      U_MEMORY_TEST_COPY(w)
+      }
+
    ~World()
       {
       U_TRACE_UNREGISTER_OBJECT(5, World)
@@ -73,6 +80,30 @@ public:
       stmt->bindResult(U_ORM_TYPE_HANDLER(randomNumber, unsigned int));
       }
 
+   // SERVICE
+
+   bool operator<(const World& other) const { return cmp_obj(&id, &other.id); }
+
+   static int cmp_obj(const void* a, const void* b)
+      {
+      U_TRACE(5, "World::cmp_obj(%p,%p)", a, b)
+
+#  ifdef U_STDCPP_ENABLE
+      /**
+       * The comparison function must follow a strict-weak-ordering
+       *
+       * 1) For all x, it is not the case that x < x (irreflexivity)
+       * 2) For all x, y, if x < y then it is not the case that y < x (asymmetry)
+       * 3) For all x, y, and z, if x < y and y < z then x < z (transitivity)
+       * 4) For all x, y, and z, if x is incomparable with y, and y is incomparable with z, then x is incomparable with z (transitivity of incomparability)
+       */
+
+      return (((const World*)a)->id < (((const World*)b)->id));
+#  else
+      return (*(const World**)a)->id < ((*(const World**)b)->id);
+#  endif
+      }
+
 #ifdef DEBUG
    const char* dump(bool breset) const
       {