From: Martin Zaun Date: October 1 2010 5:11am Subject: bzr commit into mysql-5.1-telco-7.1 branch (martin.zaun:3854) List-Archive: http://lists.mysql.com/commits/119601 Message-Id: <201010010513.o8UGIMZY031380@rcsinet13.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1988502458==" --===============1988502458== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/mz/mysql/ndb-7.1/ based on revid:jonas@stripped 3854 Martin Zaun 2010-09-30 [merge] crund - fixes and cleanups modified: storage/ndb/test/crund/config_samples/crundClusterj.properties storage/ndb/test/crund/config_samples/crundMysql.properties storage/ndb/test/crund/config_samples/crundNdbapi.properties storage/ndb/test/crund/config_samples/crundNdbjtie.properties storage/ndb/test/crund/config_samples/crundOpenjpaClusterj.properties storage/ndb/test/crund/config_samples/crundRun.properties storage/ndb/test/crund/config_samples/env.properties storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile storage/ndb/test/crund/martins_little_helpers/src/utils/helpers.hpp storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java storage/ndb/test/crund/src/crundndb/Driver.cpp storage/ndb/test/crund/src/crundndb/Operations.cpp storage/ndb/test/crund/src/crundndb/Operations.hpp storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp === modified file 'storage/ndb/test/crund/config_samples/crundClusterj.properties' --- a/storage/ndb/test/crund/config_samples/crundClusterj.properties 2010-02-25 15:00:17 +0000 +++ b/storage/ndb/test/crund/config_samples/crundClusterj.properties 2010-10-01 04:10:21 +0000 @@ -1,7 +1,7 @@ # XXX NPE with clusterj if field = null #exclude=setVarbinary1,setVarbinary1_batch,getVarbinary1,getVarbinary1_batch,setVarbinary10,setVarbinary10_batch,getVarbinary10,getVarbinary10_batch,setVarbinary100,setVarbinary100_batch,getVarbinary100,getVarbinary100_batch -exclude=navA->B0 +#exclude=navA->B0 #exclude= com.mysql.clusterj.connectstring=localhost === modified file 'storage/ndb/test/crund/config_samples/crundMysql.properties' --- a/storage/ndb/test/crund/config_samples/crundMysql.properties 2010-02-25 15:00:17 +0000 +++ b/storage/ndb/test/crund/config_samples/crundMysql.properties 2010-10-01 04:10:21 +0000 @@ -1,6 +1,6 @@ # blobs seem to work but not implemented in other backends yet -exclude=setBlob1000,getBlob1000,setBlob10000,getBlob10000,setBlob100000,getBlob100000,setText1000,getText1000,setText10000,getText10000,setText100000,getText100000 +exclude=setBlob1000,setBlob1000_batch,getBlob1000,getBlob1000_batch,setBlob10000,setBlob10000_batch,getBlob10000,getBlob10000_batch,setBlob100000,setBlob100000_batch,getBlob100000,getBlob100000_batch,setText1000,setText1000_batch,getText1000,getText1000_batch,setText10000,setText10000_batch,getText10000,getText10000_batch,setText100000,setText100000_batch,getText100000,getText100000_batch # JDBC - MySQL connection settings jdbc.url=jdbc:mysql://localhost/crunddb === modified file 'storage/ndb/test/crund/config_samples/crundNdbapi.properties' --- a/storage/ndb/test/crund/config_samples/crundNdbapi.properties 2010-02-25 15:00:17 +0000 +++ b/storage/ndb/test/crund/config_samples/crundNdbapi.properties 2010-10-01 04:10:21 +0000 @@ -3,6 +3,7 @@ #exclude=navA->B0_alt,navA->B0_alt_forceSend #exclude=navA->B0_alt_forceSend #exclude=navA->B0,navA->B0alt +#exclude=getAByPK_ar,getB0ByPK_ar,getAByPK_ar_batch,getB0ByPK_ar_batch # NDBAPI connection settings ndb.mgmdConnect=localhost === modified file 'storage/ndb/test/crund/config_samples/crundNdbjtie.properties' --- a/storage/ndb/test/crund/config_samples/crundNdbjtie.properties 2010-02-25 15:00:17 +0000 +++ b/storage/ndb/test/crund/config_samples/crundNdbjtie.properties 2010-10-01 04:10:21 +0000 @@ -2,7 +2,7 @@ # XXX not yet implemented by NdbJTie #exclude=setVarbinary1,setVarbinary1_batch,getVarbinary1,getVarbinary1_batch,setVarchar1,setVarchar1_batch,getVarchar1,getVarchar1_batch,setVarbinary10,setVarbinary10_batch,getVarbinary10,getVarbinary10_batch,setVarchar10,setVarchar10_batch,getVarchar10,getVarchar10_batch,setVarbinary100,setVarbinary100_batch,getVarbinary100,getVarbinary100_batch,setVarchar100,setVarchar100_batch,getVarchar100,getVarchar100_batch,setB0->A,setB0->A_batch,navB0->A,navB0->A_batch,navB0->A_alt,navB0->A_alt_batch,navA->B0,navA->B0_forceSend,navA->B0_alt,navA->B0_alt_forceSend,nullB0->A,nullB0->A_batch #exclude=navA->B0,navA->B0_forceSend,navA->B0_alt,navA->B0_alt_forceSend -#exclude= +#exclude=getAByPK_bb,getB0ByPK_bb,getAByPK_bb_batch,getB0ByPK_bb_batch # NDBJTIE connection settings ndb.mgmdConnect=localhost === modified file 'storage/ndb/test/crund/config_samples/crundOpenjpaClusterj.properties' --- a/storage/ndb/test/crund/config_samples/crundOpenjpaClusterj.properties 2010-02-25 15:00:17 +0000 +++ b/storage/ndb/test/crund/config_samples/crundOpenjpaClusterj.properties 2010-10-01 04:10:21 +0000 @@ -1,5 +1,6 @@ #exclude=navA->B0,navA->B0_opt +#exclude=setAByPK_bulk,setB0ByPK_bulk,setAByPK,setB0ByPK,getAByPK,getB0ByPK # OpenJPA - MySQL JDBC connection settings openjpa.ConnectionURL=jdbc:mysql://localhost/crunddb === modified file 'storage/ndb/test/crund/config_samples/crundRun.properties' --- a/storage/ndb/test/crund/config_samples/crundRun.properties 2010-02-25 15:00:17 +0000 +++ b/storage/ndb/test/crund/config_samples/crundRun.properties 2010-10-01 04:10:21 +0000 @@ -5,33 +5,35 @@ logMemUsage=false includeFullGC=false logSumOfOps=true -# the number of rows for tables A in a transaction and a scale factor +# optional number of rows per transaction with a scale factor #aStart=4 #aStart=256 #aStart=1024 -aStart=4096 +#aStart=4096 #aStart=16384 +#aStart=65536 #aEnd=4 #aEnd=256 #aEnd=1024 -aEnd=4096 +#aEnd=4096 #aEnd=16384 #aEnd=65536 -aIncr=4 +#aScale=4 -# the number of rows for tables B0 in a transaction and a scale factor +# optional number of rows per transaction with a scale factor #bStart=4 #bStart=256 #bStart=1024 -bStart=4096 +#bStart=4096 #bStart=16384 +#bStart=65536 #bEnd=4 #bEnd=256 #bEnd=1024 -bEnd=4096 +#bEnd=4096 #bEnd=16384 #bEnd=65536 -bIncr=4 +#bScale=4 # the max length (multiple of 10) up to which to scale up strings # CRUND CODE (AND SCHEMA) CURRENTLY DO NOT SUPPORT @@ -50,7 +52,8 @@ allowExtendedPC=false # the number of warmup and finally recorded runs warmupRuns=0 -hotRuns=20 +hotRuns=1 +#hotRuns=20 # CURRENT LIMITS: # === modified file 'storage/ndb/test/crund/config_samples/env.properties' --- a/storage/ndb/test/crund/config_samples/env.properties 2010-09-29 10:02:15 +0000 +++ b/storage/ndb/test/crund/config_samples/env.properties 2010-10-01 04:10:21 +0000 @@ -48,8 +48,8 @@ MYSQL_LIBEXEC="$MYSQL_HOME/libexec" # - Martin's Little Helpers utilities (see below) #JAVA_INCLUDEOPTS=-I"/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers" -#JAVA_INCLUDEOPTS=-I"/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Headers" -JAVA_INCLUDEOPTS=-I"/usr/lib/jvm/java-6-sun/include" -I"/usr/lib/jvm/java-6-sun/include/linux" +JAVA_INCLUDEOPTS=-I"/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Headers" +#JAVA_INCLUDEOPTS=-I"/usr/lib/jvm/java-6-sun/include" -I"/usr/lib/jvm/java-6-sun/include/linux" # Comments: # === modified file 'storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile' --- a/storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile 2010-09-29 10:02:15 +0000 +++ b/storage/ndb/test/crund/martins_little_helpers/src/utils/Makefile 2010-10-01 04:10:21 +0000 @@ -17,8 +17,10 @@ include ../../../env.properties # -DHRT_CPUTIME_METHOD=HRT_USE_GETRUSAGE \ DDEFINES = \ - -DHRT_REALTIME_METHOD=HRT_USE_CLOCK_GETTIME \ - -DHRT_CPUTIME_METHOD=HRT_USE_CLOCK_GETTIME \ + -DHRT_REALTIME_METHOD=HRT_USE_GETTIMEOFDAY \ + -DHRT_CPUTIME_METHOD=HRT_USE_GETRUSAGE \ + #-DHRT_REALTIME_METHOD=HRT_USE_CLOCK_GETTIME \ + #-DHRT_CPUTIME_METHOD=HRT_USE_CLOCK_GETTIME \ #-DHRT_REALTIME_METHOD=HRT_USE_GETTIMEOFDAY \ #-DHRT_CPUTIME_METHOD=HRT_USE_GETRUSAGE \ #-DHRT_REALTIME_METHOD=HRT_USE_TIMES \ @@ -66,8 +68,8 @@ include ../../../env.properties # LOADLIBES for libs for the individual case # check with non-gnu makes: use of LOADLIBES, LDLIBS # CLOCK_GETTIME requires -lrt -# LDLIBS = - LDLIBS = -lrt + LDLIBS = +# LDLIBS = -lrt #------------------------------------------------------------------------------ === modified file 'storage/ndb/test/crund/martins_little_helpers/src/utils/helpers.hpp' --- a/storage/ndb/test/crund/martins_little_helpers/src/utils/helpers.hpp 2010-02-14 05:05:31 +0000 +++ b/storage/ndb/test/crund/martins_little_helpers/src/utils/helpers.hpp 2010-10-01 04:10:21 +0000 @@ -36,11 +36,11 @@ using std::flush; * Helper Macros & Functions ************************************************************/ -// gcc: crashes when printing source code file number: -// << ", line: " << (__LINE__) +// JNI crashes with gcc & operator<<(ostream &, long/int) // so, we use C99's __func__ and also convert to string using sprintf() #define ABORT_ERROR(message) \ - do { char l[1024]; \ + do { \ + char l[1024]; \ sprintf(l, "%d", __LINE__); \ cout << "!!! error, file: " << (__FILE__) \ << ", function: " << (__func__) \ === modified file 'storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp' --- a/storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp 2010-02-14 05:05:31 +0000 +++ b/storage/ndb/test/crund/martins_little_helpers/src/utils/string_helpers.hpp 2010-10-01 04:10:21 +0000 @@ -8,6 +8,7 @@ //#include #include +#include #include #include @@ -20,6 +21,7 @@ namespace utils { using std::string; using std::wstring; using std::ostream; +using std::wistringstream; using std::set; /************************************************************ @@ -59,14 +61,47 @@ toBool(const wstring& ws) } /** + * Parses a wide character string as a (signed) decimal integer. + * + * Returns the integral value of a wide character string, the default value + * if the string is empty, or the error value if the conversion has failed. + */ +template< typename I > +inline I +toI(const wstring& ws, I vdefault, I verror) +{ + I val; + if (ws.length() == 0) { + val = vdefault; + } else { + wistringstream wiss(ws); + wiss >> val; + if (wiss.fail() || !wiss.eof()) { + val = verror; + } + } + return val; +} + +inline int +toInt(const wstring& ws, int vdefault, int verror) +{ + return toI< int >(ws, vdefault, verror); +} + +/** * Returns the character representation of an int. */ inline string toString(int i) { - std::ostringstream o; - o << i; - return o.str(); + // JNI crashes with gcc & operator<<(ostream &, long/int) + //std::ostringstream o; + //o << i; + //return o.str(); + char s[256]; + snprintf(s, 256, "%d", i); + return string(s); } /** @@ -86,36 +121,6 @@ toString(const wstring& ws) } /** - * Inserts all elements of a set s into the output stream os. - */ -/* -// neither matches operator<< in: set s ; cout << s; - -inline ostream & -operator<< (ostream & os, const set< string >& s) -{ - os << "{"; - set< string >::iterator i = s.begin(); - if (i != s.end()) { - os << *i; - while (++i != s.end()) - os << "," << *i; - } - os << "}"; - return os; -} - -template< typename T > -inline ostream & -operator<< (ostream& os, const set< T >& s) -{ - typename set< T >::iterator i = s.begin(); -... -} - -*/ - -/** * Returns a string representation of all elements in the set. * * This function is not very efficient in that it involves multiple @@ -125,19 +130,19 @@ inline string toString(const set< string >& s) { string r; - r += "{"; + r += "["; set< string >::iterator i = s.begin(); if (i != s.end()) { r += "\""; r += *i; r += "\""; while (++i != s.end()) { - r += ",\""; + r += ", \""; r += *i; r += "\""; } } - r += "}"; + r += "]"; return r; } === modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java' --- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java 2010-03-01 19:10:54 +0000 +++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java 2010-10-01 04:10:21 +0000 @@ -89,23 +89,25 @@ abstract public class Driver { // benchmark settings protected final Properties props = new Properties(); protected String descr = ""; - protected boolean logRealTime = false; - protected boolean logMemUsage = false; - protected boolean includeFullGC = false; - protected boolean logSumOfOps = false; - protected boolean renewOperations = false; - protected boolean renewConnection = false; - protected boolean allowExtendedPC = false; - protected int aRows = (1 << 8); - protected int bRows = (1 << 8); - protected int aStart = (1 << 8), aEnd = (1 << 12), aIncr = (1 << 2); - protected int bStart = (1 << 8), bEnd = (1 << 12), bIncr = (1 << 2); - protected int maxVarbinaryBytes = 100; - protected int maxVarcharChars = 100; - protected int maxBlobBytes = 1000; - protected int maxTextChars = 1000; - protected int warmupRuns = 0; - protected int hotRuns = 0; + protected boolean logRealTime; + protected boolean logMemUsage; + protected boolean includeFullGC; + protected boolean logSumOfOps; + protected boolean renewOperations; + protected boolean renewConnection; + protected boolean allowExtendedPC; + protected int aStart; + protected int bStart; + protected int aEnd; + protected int bEnd; + protected int aScale; + protected int bScale; + protected int maxVarbinaryBytes; + protected int maxVarcharChars; + protected int maxBlobBytes; + protected int maxTextChars; + protected int warmupRuns; + protected int hotRuns; protected final Set exclude = new HashSet(); // ---------------------------------------------------------------------- @@ -263,9 +265,10 @@ abstract public class Driver { init(); // warmup runs - for (int i = 0; i < warmupRuns; i++) + for (int i = 0; i < warmupRuns; i++) { runTests(); - + } + // truncate log file, reset log buffers out.println(); out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); @@ -280,9 +283,10 @@ abstract public class Driver { openLogFile(); // hot runs - for (int i = 0; i < hotRuns; i++) + for (int i = 0; i < hotRuns; i++) { runTests(); - + } + // write log buffers if (logRealTime) { log.println(descr + ", rtime[ms]" @@ -311,7 +315,6 @@ abstract public class Driver { loadProperties(); initProperties(); printProperties(); - checkProperties(); openLogFile(); // init log buffers @@ -383,7 +386,12 @@ abstract public class Driver { * Initializes the benchmark properties. */ protected void initProperties() { - // initialize boolean/numeric properties + //props.list(out); + out.print("initializing properties ... "); + + final StringBuilder msg = new StringBuilder(); + final String eol = System.getProperty("line.separator"); + logRealTime = parseBoolean("logRealTime"); logMemUsage = parseBoolean("logMemUsage"); includeFullGC = parseBoolean("includeFullGC"); @@ -391,14 +399,39 @@ abstract public class Driver { renewOperations = parseBoolean("renewOperations"); renewConnection = parseBoolean("renewConnection"); allowExtendedPC = parseBoolean("allowExtendedPC"); - aRows = parseInt("aRows", 0); - bRows = parseInt("bRows", 0); - aStart = parseInt("aStart", 0); - aEnd = parseInt("aEnd", 0); - aIncr = parseInt("aIncr", 0); - bStart = parseInt("bStart", 0); - bEnd = parseInt("bEnd", 0); - bIncr = parseInt("bIncr", 0); + + aStart = parseInt("aStart", 256); + if (aStart < 1) { + msg.append("[ignored] aStart: " + aStart + eol); + aStart = 256; + } + aEnd = parseInt("aEnd", aStart); + if (aEnd < aStart) { + msg.append("[ignored] aEnd: "+ aEnd + eol); + aEnd = aStart; + } + aScale = parseInt("aScale", 2); + if (aScale < 2) { + msg.append("[ignored] aScale: " + aScale + eol); + aScale = 2; + } + + bStart = parseInt("bStart", 256); + if (bStart < 1) { + msg.append("[ignored] bStart: " + bStart + eol); + bStart = 256; + } + bEnd = parseInt("bEnd", bStart); + if (bEnd < bStart) { + msg.append("[ignored] bEnd: " + bEnd + eol); + bEnd = bStart; + } + bScale = parseInt("bScale", 2); + if (bScale < 2) { + msg.append("[ignored] bScale: " + bScale + eol); + bScale = 2; + } + maxVarbinaryBytes = parseInt("maxVarbinaryBytes", 100); maxVarcharChars = parseInt("maxVarcharChars", 100); maxBlobBytes = parseInt("maxBlobBytes", 1000); @@ -411,13 +444,22 @@ abstract public class Driver { for (int i = 0; i < e.length; i++) { exclude.add(e[i]); } - } + if (msg.length() == 0) { + out.println("[ok]"); + } else { + out.println(); + out.print(msg.toString()); + } + out.println("data set: " + + "[A=" + aStart + ".." + aEnd + + ", B=" + bStart + ".." + bEnd + "]"); + } + /** * Prints the benchmark's properties. */ protected void printProperties() { - //props.list(out); out.println(); out.println("main settings:"); out.println("logRealTime: " + logRealTime); @@ -427,14 +469,12 @@ abstract public class Driver { out.println("renewOperations: " + renewOperations); out.println("renewConnection: " + renewConnection); out.println("allowExtendedPC: " + allowExtendedPC); - out.println("aRows: " + aRows); out.println("aStart: " + aStart); - out.println("aEnd: " + aEnd); - out.println("aIncr: " + aIncr); - out.println("bRows: " + bRows); out.println("bStart: " + bStart); + out.println("aEnd: " + aEnd); out.println("bEnd: " + bEnd); - out.println("bIncr: " + bIncr); + out.println("aScale: " + aScale); + out.println("bScale: " + bScale); out.println("maxVarbinaryBytes: " + maxVarbinaryBytes); out.println("maxVarcharChars: " + maxVarcharChars); out.println("maxBlobBytes: " + maxBlobBytes); @@ -445,109 +485,6 @@ abstract public class Driver { } /** - * Checks the benchmark's properties. - */ - protected void checkProperties() { - out.println(); - out.print("checking properties ... "); - final StringBuilder msg = new StringBuilder(); - final String eol = System.getProperty("line.separator"); - if (aRows > 0) { - if (aStart > 0) { - msg.append("[ignored] aStart: "); - msg.append(aStart); - msg.append(eol); - } - if (aEnd > 0) { - msg.append("[ignored] aEnd: "); - msg.append(aEnd); - msg.append(eol); - } - if (aIncr > 0) { - msg.append("[ignored] aIncr: "); - msg.append(aIncr); - msg.append(eol); - } - aStart = aRows; - aEnd = aRows; - aIncr = 2; - } else { - if (aStart <= 0) { - aStart = (1 << 8); - msg.append("[changed] aStart: "); - msg.append(aStart); - msg.append(eol); - } - if (aEnd < aStart) { - aEnd = aStart; - msg.append("[changed] aEnd: "); - msg.append(aEnd); - msg.append(eol); - } - if (aIncr <= 1) { - aIncr = 2; - msg.append("[changed] aIncr: "); - msg.append(aIncr); - msg.append(eol); - } - } - if (bRows > 0) { - if (bRows < aRows) { - bRows = aRows; - msg.append("[changed] bRows: "); - msg.append(bRows); - msg.append(eol); - } - if (bStart > 0) { - msg.append("[ignored] bStart: "); - msg.append(bStart); - msg.append(eol); - } - if (bEnd > 0) { - msg.append("[ignored] bEnd: "); - msg.append(bEnd); - msg.append(eol); - } - if (bIncr > 0) { - msg.append("[ignored] bIncr: "); - msg.append(bIncr); - msg.append(eol); - } - bStart = bRows; - bEnd = bRows; - bIncr = 2; - } else { - if (bStart < aStart) { - bStart = aStart; - msg.append("[changed] bStart: "); - msg.append(bStart); - msg.append(eol); - } - if (bEnd < bStart) { - bEnd = bStart; - msg.append("[changed] bEnd: "); - msg.append(bEnd); - msg.append(eol); - } - if (bIncr <= 1) { - bIncr = 2; - msg.append("[changed] bIncr: "); - msg.append(bIncr); - msg.append(eol); - } - } - if (msg.length() == 0) { - out.println("[ok]"); - } else { - out.println(); - out.print(msg.toString()); - } - out.println("data range: " - + "[A=" + aStart + ".." + aEnd - + ", B=" + bStart + ".." + bEnd + "]"); - } - - /** * Opens the benchmark's data log file. */ private void openLogFile() throws IOException { @@ -578,9 +515,10 @@ abstract public class Driver { initConnection(); initOperations(); - for (int i = aStart; i <= aEnd; i *= aIncr) { - //for (int j = bBeg; j <= bEnd; j *= bIncr) - for (int j = (i > bStart ? i : bStart); j <= bEnd; j *= bIncr) { + assert (aStart <= aEnd && aScale > 1); + assert (bStart <= bEnd && bScale > 1); + for (int i = aStart; i <= aEnd; i *= aScale) { + for (int j = bStart; j <= bEnd; j *= bScale) { try { runOperations(i, j); } catch (Exception ex) { @@ -606,8 +544,14 @@ abstract public class Driver { protected void runOperations(int countA, int countB) throws Exception { out.println(); out.println("------------------------------------------------------------"); - out.println("countA = " + countA + ", countB = " + countB); - out.println(); + + if (countA > countB) { + out.println("skipping operations ... " + + "[A=" + countA + ", B=" + countB + "]"); + return; + } + out.println("running operations ... " + + "[A=" + countA + ", B=" + countB + "]"); // log buffers if (logRealTime) { @@ -653,7 +597,8 @@ abstract public class Driver { rtimes.append("\t" + ta); out.println(); out.println("total"); - out.println("tx real time = " + ta + "\tms [begin..commit]"); + out.println("tx real time\t\t= " + ta + + "\tms [begin..commit]"); } rtimes.append(endl); } @@ -662,7 +607,7 @@ abstract public class Driver { musage.append("\t" + ma); out.println(); out.println("total"); - out.println("net mem usage = " + (ma >= 0 ? "+" : "") + ma + out.println("net mem usage\t\t= " + (ma >= 0 ? "+" : "") + ma + "\tKiB"); } musage.append(endl); @@ -718,7 +663,8 @@ abstract public class Driver { //t1 = System.currentTimeMillis(); t1 = System.nanoTime() / 1000000; final long t = t1 - t0; - out.println("tx real time = " + t + "\tms [begin..commit]"); + out.println("tx real time\t\t= " + t + + "\tms [begin..commit]"); //rtimes.append("\t" + (Math.round(t / 100.0) / 10.0)); rtimes.append("\t" + t); ta += t; @@ -731,16 +677,8 @@ abstract public class Driver { final long m0K = (m0 / 1024); final long m1K = (m1 / 1024); final long mK = m1K - m0K; - out.println("net mem usage = " + (mK >= 0 ? "+" : "") + mK + out.println("net mem usage\t\t= " + (mK >= 0 ? "+" : "") + mK + "\tKiB [" + m0K + "K->" + m1K + "K]"); -/* - out.println("allocated memory = " - + m1 + "\tK after commit"); - out.println("total memory = " - + (rt.totalMemory() / 1024) + "\tK after commit"); - out.println("max memory = " - + (rt.maxMemory() / 1024) + "\tK after commit"); -*/ musage.append("\t" + mK); ma += mK; } === modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java' --- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java 2010-03-01 19:10:54 +0000 +++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbApiLoad.java 2010-10-01 04:10:21 +0000 @@ -50,32 +50,23 @@ public class NdbApiLoad extends NdbBase loadSystemLibrary("crundndb"); // initialize NDB resources - out.println(); - try { - final int ret = ndbinit(mgmdConnect); - if (ret != 0) { - err.println("NdbApiLoad: failed initializing NDBAPI;" - + " return value = " + ret); - } - } catch (RuntimeException e) { - err.println("NdbApiLoad: failed initializing NDBAPI;" - + " caught exception: " + e); - throw e; + final int ret = ndbinit(mgmdConnect); + if (ret != 0) { + String msg = ("NdbApiLoad: failed initializing NDBAPI;" + + " return value = " + ret); + err.println(msg); + throw new Exception(msg); } } protected void close() throws Exception { // release NDB resources - try { - final int ret = ndbclose(); - if (ret != 0) { - err.println("NdbApiLoad: failed closing NDBAPI;" - + " return value = " + ret); - } - } catch (RuntimeException e) { - err.println("NdbApiLoad: failed closing NDBAPI;" - + " caught exception: " + e); - throw e; + final int ret = ndbclose(); + if (ret != 0) { + String msg = ("NdbApiLoad: failed closing NDBAPI;" + + " return value = " + ret); + err.println(msg); + throw new Exception(msg); } super.close(); } @@ -107,10 +98,14 @@ public class NdbApiLoad extends NdbBase boolean batch); protected native void setB0ByPK(int countA, int countB, boolean batch); - protected native void getAByPK(int countA, int countB, - boolean batch); - protected native void getB0ByPK(int countA, int countB, - boolean batch); + protected native void getAByPK_bb(int countA, int countB, + boolean batch); + protected native void getB0ByPK_bb(int countA, int countB, + boolean batch); + protected native void getAByPK_ar(int countA, int countB, + boolean batch); + protected native void getB0ByPK_ar(int countA, int countB, + boolean batch); protected native void setVarbinary(int countA, int countB, boolean batch, int length); protected native void getVarbinary(int countA, int countB, @@ -171,16 +166,30 @@ public class NdbApiLoad extends NdbBase }); ops.add( - new Op("getAByPK" + (batch ? "_batch" : "")) { + new Op("getAByPK_bb" + (batch ? "_batch" : "")) { + public void run(int countA, int countB) { + getAByPK_bb(countA, countB, batch); + } + }); + + ops.add( + new Op("getAByPK_ar" + (batch ? "_batch" : "")) { + public void run(int countA, int countB) { + getAByPK_ar(countA, countB, batch); + } + }); + + ops.add( + new Op("getB0ByPK_bb" + (batch ? "_batch" : "")) { public void run(int countA, int countB) { - getAByPK(countA, countB, batch); + getB0ByPK_bb(countA, countB, batch); } }); ops.add( - new Op("getB0ByPK" + (batch ? "_batch" : "")) { + new Op("getB0ByPK_ar" + (batch ? "_batch" : "")) { public void run(int countA, int countB) { - getB0ByPK(countA, countB, batch); + getB0ByPK_ar(countA, countB, batch); } }); === modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java' --- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java 2010-02-14 05:05:31 +0000 +++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbBase.java 2010-10-01 04:10:21 +0000 @@ -53,8 +53,8 @@ abstract public class NdbBase extends Dr protected void printProperties() { super.printProperties(); - out.println("ndb.mgmdConnect " + mgmdConnect); - out.println("ndb.catalog " + catalog); - out.println("ndb.schema " + schema); + out.println("ndb.mgmdConnect \"" + mgmdConnect + "\""); + out.println("ndb.catalog \"" + catalog + "\""); + out.println("ndb.schema \"" + schema + "\""); } } === modified file 'storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java' --- a/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java 2010-09-27 05:31:17 +0000 +++ b/storage/ndb/test/crund/src/com/mysql/cluster/crund/NdbJTieLoad.java 2010-10-01 04:10:21 +0000 @@ -182,12 +182,11 @@ public class NdbJTieLoad extends NdbBase // instantiate NDB cluster singleton out.println(); - out.print("creating cluster conn..."); + out.print("creating cluster conn ..."); out.flush(); mgmd = Ndb_cluster_connection.create(mgmdConnect); assert mgmd != null; - //out.println(" [ok]"); - out.println(" [ok, mgmd=" + mgmd + "]"); + out.println(" [ok, mgmd=" + mgmd + "]"); // connect to cluster management node (ndb_mgmd) out.print("connecting to mgmd ..."); @@ -222,7 +221,6 @@ public class NdbJTieLoad extends NdbBase out.flush(); final int initial_wait = 10; // secs to wait until first node detected final int final_wait = 0; // secs to wait after first node detected - // returns: 0 all nodes live, > 0 at least one node live, < 0 error if (mgmd.wait_until_ready(initial_wait, final_wait) < 0) { final String msg = ("data nodes were not ready within " @@ -232,10 +230,9 @@ public class NdbJTieLoad extends NdbBase } out.println(" [ok]"); - // connect to database - out.println(); - out.println("connecting to database..."); + out.print("connecting to database..."); + out.flush(); ndb = Ndb.create(mgmd, catalog, schema); final int max_no_tx = 10; // maximum number of parallel tx (<=1024) // note each scan or index scan operation uses one extra transaction @@ -346,7 +343,7 @@ public class NdbJTieLoad extends NdbBase }); ops.add( - new Op("clearVarbinary" + (batch ? "_batch" : "")) { + new Op("clearVarbinary" + l + (batch ? "_batch" : "")) { public void run(int countA, int countB) { setVarbinary(meta.table_B0, 1, countB, batch, null); } @@ -370,6 +367,13 @@ public class NdbJTieLoad extends NdbBase getVarchar(meta.table_B0, 1, countB, batch, s); } }); + + ops.add( + new Op("clearVarchar" + l + (batch ? "_batch" : "")) { + public void run(int countA, int countB) { + setVarchar(meta.table_B0, 1, countB, batch, null); + } + }); } ops.add( === modified file 'storage/ndb/test/crund/src/crundndb/Driver.cpp' --- a/storage/ndb/test/crund/src/crundndb/Driver.cpp 2010-02-14 05:05:31 +0000 +++ b/storage/ndb/test/crund/src/crundndb/Driver.cpp 2010-10-01 04:10:21 +0000 @@ -64,11 +64,14 @@ protected: bool logSumOfOps; bool renewConnection; bool renewOperations; - unsigned int aStart, aEnd, aIncr; - unsigned int bStart, bEnd, bIncr; - unsigned int maxStringLength; - unsigned int warmupRuns; - unsigned int hotRuns; + int aStart, aEnd, aScale; + int bStart, bEnd, bScale; + int maxVarbinaryBytes; + int maxVarcharChars; + int maxBlobBytes; + int maxTextChars; + int warmupRuns; + int hotRuns; set< string > exclude; // the NDB database connection @@ -133,6 +136,16 @@ protected: void printProperties(); /** + * Opens the benchmark's data log file. + */ + void openLogFile(); + + /** + * Closes the benchmark's data log file. + */ + void closeLogFile(); + + /** * Initializes the benchmark's resources. */ void init(); @@ -187,27 +200,36 @@ protected: void clearData(); // operation invocation templates - template< bool, bool > struct DelAllOp; + template< bool > struct ADelAllOp; - template< bool, bool, bool > struct InsOp; + template< bool > struct B0DelAllOp; + + template< bool, bool > struct AInsOp; + + template< bool, bool > struct B0InsOp; + + template< const char** opName, + void (crund_ndb::Operations::*OP)(const NdbDictionary::Table*, + int,int,bool), + bool batch > + struct AByPKOp; template< const char** opName, - bool isTableA, void (crund_ndb::Operations::*OP)(const NdbDictionary::Table*, int,int,bool), bool batch > - struct byPKOp; + struct B0ByPKOp; template< const char** opName, void (crund_ndb::Operations::*OP)(const NdbDictionary::Table*, int,int,bool,int), bool batch > - struct lengthOp; + struct LengthOp; template< const char** opName, void (crund_ndb::Operations::*OP)(int,int,bool), bool forceSend > - struct relOp; + struct RelOp; }; } // crund_ndb @@ -224,6 +246,7 @@ using std::string; using std::wstring; using utils::toBool; +using utils::toInt; using utils::toString; using crund_ndb::Driver; @@ -242,23 +265,23 @@ Driver::run() { init(); // warmup runs - for (unsigned int i = 0; i < warmupRuns; i++) + for (int i = 0; i < warmupRuns; i++) { runTests(); - + } + // truncate log file, reset log buffers cout << endl << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl << "start logging results ..." << endl << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl << endl; - log.close(); - log.open(logFileName.c_str(), ios_base::out | ios_base::trunc); - assert (log.good()); header.rdbuf()->str(""); rtimes.rdbuf()->str(""); + closeLogFile(); + openLogFile(); // hot runs - for (unsigned int i = 0; i < hotRuns; i++) { + for (int i = 0; i < hotRuns; i++) { runTests(); } @@ -284,22 +307,17 @@ Driver::init() { loadProperties(); initProperties(); printProperties(); - - // initialize the benchmark's resources - ops = new crund_ndb::Operations(); - assert (!mgmdConnect.empty()); - ops->init(mgmdConnect.c_str()); - - // open the benchmark's data log file - cout << endl; - cout << "writing results to file: " << logFileName << endl; - log.open(logFileName.c_str()); - assert (log.good()); + openLogFile(); // clear log buffers logHeader = true; header.rdbuf()->str(""); rtimes.rdbuf()->str(""); + + // initialize the benchmark's resources + ops = new crund_ndb::Operations(); + assert (!mgmdConnect.empty()); + ops->init(mgmdConnect.c_str()); } void @@ -308,16 +326,13 @@ Driver::close() { header.rdbuf()->str(""); rtimes.rdbuf()->str(""); - // close the benchmark's data log file - cout << "closing files ... " << flush; - log.close(); - cout << " [ok]" << endl; - // release the benchmark's resources assert (!mgmdConnect.empty()); ops->close(); delete ops; ops = NULL; + + closeLogFile(); } void @@ -338,38 +353,95 @@ Driver::loadProperties() { void Driver::initProperties() { - descr = ""; - logRealTime = false; - logCpuTime = false; - logSumOfOps = false; - renewConnection = false; - renewOperations = false; - aStart = (1 << 8), aEnd = (1 << 12), aIncr = (1 << 2); - bStart = (1 << 8), bEnd = (1 << 12), bIncr = (1 << 2); - maxStringLength = 100; - warmupRuns = 0; - hotRuns = 1; - mgmdConnect = "localhost"; - catalog = ""; - schema = ""; + cout << "initializing properties ... " << flush; + + ostringstream msg; - // initialize boolean properties logRealTime = toBool(props[L"logRealTime"]); logCpuTime = toBool(props[L"logCpuTime"]); logSumOfOps = toBool(props[L"logSumOfOps"]); renewOperations = toBool(props[L"renewOperations"]); renewConnection = toBool(props[L"renewConnection"]); - - // initialize numeric properties - wistringstream(props[L"aStart"]) >> aStart; - wistringstream(props[L"aEnd"]) >> aEnd; - wistringstream(props[L"aIncr"]) >> aIncr; - wistringstream(props[L"bStart"]) >> bStart; - wistringstream(props[L"bEnd"]) >> bEnd; - wistringstream(props[L"bIncr"]) >> bIncr; - wistringstream(props[L"maxStringLength"]) >> maxStringLength; - wistringstream(props[L"warmupRuns"]) >> warmupRuns; - wistringstream(props[L"hotRuns"]) >> hotRuns; + + aStart = toInt(props[L"aStart"], 256, 0); + if (aStart < 1) { + msg << "[ignored] aStart: '" + << toString(props[L"aStart"]) << "'" << endl; + aStart = 256; + } + aEnd = toInt(props[L"aEnd"], aStart, 0); + if (aEnd < aStart) { + msg << "[ignored] aEnd: '" + << toString(props[L"aEnd"]) << "'" << endl; + aEnd = aStart; + } + aScale = toInt(props[L"aScale"], 2, 0); + if (aScale < 2) { + msg << "[ignored] aScale: '" + << toString(props[L"aScale"]) << "'" << endl; + aScale = 2; + } + + bStart = toInt(props[L"bStart"], aStart, 0); + if (bStart < 1) { + msg << "[ignored] bStart: '" + << toString(props[L"bStart"]) << "'" << endl; + bStart = aStart; + } + bEnd = toInt(props[L"bEnd"], bStart, 0); + if (bEnd < bStart) { + msg << "[ignored] bEnd: '" + << toString(props[L"bEnd"]) << "'" << endl; + bEnd = bStart; + } + bScale = toInt(props[L"bScale"], 2, 0); + if (bScale < 2) { + msg << "[ignored] bScale: '" + << toString(props[L"bScale"]) << "'" << endl; + bScale = 2; + } + + maxVarbinaryBytes = toInt(props[L"maxVarbinaryBytes"], 100, 0); + if (maxVarbinaryBytes < 1) { + msg << "[ignored] maxVarbinaryBytes: '" + << toString(props[L"maxVarbinaryBytes"]) << "'" << endl; + maxVarbinaryBytes = 100; + } + + maxVarcharChars = toInt(props[L"maxVarcharChars"], 100, 0); + if (maxVarcharChars < 1) { + msg << "[ignored] maxVarcharChars: '" + << toString(props[L"maxVarcharChars"]) << "'" << endl; + maxVarcharChars = 100; + } + + maxBlobBytes = toInt(props[L"maxBlobBytes"], 1000, 0); + if (maxBlobBytes < 1) { + msg << "[ignored] maxBlobBytes: '" + << toString(props[L"maxBlobBytes"]) << "'" << endl; + maxBlobBytes = 1000; + } + + maxTextChars = toInt(props[L"maxTextChars"], 1000, 0); + if (maxTextChars < 1) { + msg << "[ignored] maxTextChars: '" + << toString(props[L"maxTextChars"]) << "'" << endl; + maxTextChars = 1000; + } + + warmupRuns = toInt(props[L"warmupRuns"], 0, -1); + if (warmupRuns < 0) { + msg << "[ignored] warmupRuns: '" + << toString(props[L"warmupRuns"]) << "'" << endl; + warmupRuns = 0; + } + + hotRuns = toInt(props[L"hotRuns"], 1, -1); + if (hotRuns < 0) { + msg << "[ignored] hotRuns: '" + << toString(props[L"hotRuns"]) << "'" << endl; + hotRuns = 1; + } // initialize exclude set const wstring& estr = props[L"exclude"]; @@ -397,11 +469,18 @@ Driver::initProperties() { schema = toString(props[L"ndb.schema"]); descr = "C++->NDBAPI(" + mgmdConnect + ")"; + + if (msg.tellp() == 0) { + cout << "[ok]" << endl; + } else { + cout << endl << msg.str() << endl; + } + + cout << "data set: " + << "[A=" << aStart << ".." << aEnd + << ", B=" << bStart << ".." << bEnd << "]" << endl; } -/** - * Prints the benchmark's properties. - */ void Driver::printProperties() { const ios_base::fmtflags f = cout.flags(); @@ -409,19 +488,22 @@ Driver::printProperties() { //cout << ios_base::boolalpha; cout.flags(ios_base::boolalpha); - cout << "main settings:" << endl; + cout << endl << "main settings:" << endl; cout << "logRealTime: " << logRealTime << endl; cout << "logCpuTime: " << logCpuTime << endl; cout << "logSumOfOps: " << logSumOfOps << endl; cout << "renewOperations: " << renewOperations << endl; cout << "renewConnection: " << renewConnection << endl; cout << "aStart: " << aStart << endl; - cout << "aEnd: " << aEnd << endl; - cout << "aIncr: " << aIncr << endl; cout << "bStart: " << bStart << endl; + cout << "aEnd: " << aEnd << endl; cout << "bEnd: " << bEnd << endl; - cout << "bIncr: " << bIncr << endl; - cout << "maxStringLength: " << maxStringLength << endl; + cout << "aScale: " << aScale << endl; + cout << "bScale: " << bScale << endl; + cout << "maxVarbinaryBytes: " << maxVarbinaryBytes << endl; + cout << "maxVarcharChars: " << maxVarcharChars << endl; + cout << "maxBlobBytes: " << maxBlobBytes << endl; + cout << "maxTextChars: " << maxTextChars << endl; cout << "warmupRuns: " << warmupRuns << endl; cout << "hotRuns: " << hotRuns << endl; cout << "exclude: " << toString(exclude) << endl; @@ -432,6 +514,22 @@ Driver::printProperties() { cout.flags(f); } +void +Driver::openLogFile() { + cout << endl + << "writing results to file: " << logFileName << endl; + //log.open(logFileName.c_str()); + log.open(logFileName.c_str(), ios_base::out | ios_base::trunc); + assert (log.good()); +} + +void +Driver::closeLogFile() { + cout << "closing files ... " << flush; + log.close(); + cout << " [ok]" << endl; +} + // ---------------------------------------------------------------------- void @@ -439,9 +537,10 @@ Driver::runTests() { initConnection(); initOperations(); - for (unsigned int i = aStart; i <= aEnd; i *= aIncr) { - //for (int j = bBeg; j <= bEnd; j *= bIncr) - for (unsigned int j = (i > bStart ? i : bStart); j <= bEnd; j *= bIncr) { + assert(aStart <= aEnd && aScale > 1); + assert(bStart <= bEnd && bScale > 1); + for (int i = aStart; i <= aEnd; i *= aScale) { + for (int j = bStart; j <= bEnd; j *= bScale) { runOperations(i, j); } } @@ -458,9 +557,15 @@ Driver::runTests() { void Driver::runOperations(int countA, int countB) { cout << endl - << "------------------------------------------------------------" << endl - << "countA = " << countA << ", countB = " << countB << endl - << endl; + << "------------------------------------------------------------" << endl; + + if (countA > countB) { + cout << "skipping operations ... " + << "[A=" << countA << ", B=" << countB << "]" << endl; + return; + } + cout << "running operations ... " + << "[A=" << countA << ", B=" << countB << "]" << endl; // log buffers if (logRealTime) { @@ -507,7 +612,7 @@ Driver::runOperations(int countA, int co rtimes << "\t" << rta; cout << endl << "total" << endl - << "tx real time = " << rta + << "tx real time\t\t= " << rta << "\tms [begin..commit]" << endl; } rtimes << endl; @@ -517,7 +622,7 @@ Driver::runOperations(int countA, int co ctimes << "\t" << cta; cout << endl << "total" << endl - << "tx cpu time = " << cta + << "tx cpu time\t\t= " << cta << "\tms [begin..commit]" << endl; } ctimes << endl; @@ -570,7 +675,7 @@ Driver::commit(const string& name) { rtimes << "\tERROR"; } else { long t = long(hrt_rtmicros(&t1.rtstamp, &t0.rtstamp)/1000); - cout << "tx real time = " << t + cout << "tx real time\t\t= " << t << "\tms [begin..commit]" << endl; rtimes << "\t" << t; rta += t; @@ -583,7 +688,7 @@ Driver::commit(const string& name) { ctimes << "\tERROR"; } else { long t = long(hrt_ctmicros(&t1.ctstamp, &t0.ctstamp)/1000); - cout << "tx cpu time = " << t + cout << "tx cpu time\t\t= " << t << "\tms [begin..commit]" << endl; ctimes << "\t" << t; cta += t; @@ -620,47 +725,81 @@ Driver::initOperations() { // the operation invocation templates look a bit complex, but they help // a lot to factorize code over the operations' parameter signatures -template< bool tableA, bool batch > -struct Driver::DelAllOp : Op { - DelAllOp() : Op(string(string(tableA ? "delAllA" : "delAllB0") - + (batch ? "_batch" : ""))) { +template< bool batch > +struct Driver::ADelAllOp : Op { + ADelAllOp() : Op(string("delAllA") + + (batch ? "_batch" : "")) { + } + + virtual void run(int countA, int countB) const { + int count; + ops->delByScan(ops->meta->table_A, count, batch); + assert (count == countA); + } +}; + +template< bool batch > +struct Driver::B0DelAllOp : Op { + B0DelAllOp() : Op(string("delAllB0") + + (batch ? "_batch" : "")) { } virtual void run(int countA, int countB) const { int count; - ops->delByScan((tableA ? ops->meta->table_A : ops->meta->table_B0), - count, batch); - assert (count == (tableA ? countA : countB)); + ops->delByScan(ops->meta->table_B0, count, batch); + assert (count == countB); + } +}; + +template< bool setAttrs, bool batch > +struct Driver::AInsOp : Op { + AInsOp() : Op(string("insA") + + (setAttrs ? "_attr" : "") + + (batch ? "_batch" : "")) { + } + + virtual void run(int countA, int countB) const { + ops->ins(ops->meta->table_A, 1, countA, setAttrs, batch); } }; -template< bool tableA, bool setAttrs, bool batch > -struct Driver::InsOp : Op { - InsOp() : Op(string(string(tableA ? "insA" : "insB0") - + (setAttrs ? "_attr" : "") - + (batch ? "_batch" : ""))) { +template< bool setAttrs, bool batch > +struct Driver::B0InsOp : Op { + B0InsOp() : Op(string("insB0") + + (setAttrs ? "_attr" : "") + + (batch ? "_batch" : "")) { } virtual void run(int countA, int countB) const { - ops->ins((tableA ? ops->meta->table_A : ops->meta->table_B0), - 1, (tableA ? countA : countB), setAttrs, batch); + ops->ins(ops->meta->table_B0, 1, countB, setAttrs, batch); } }; template< const char** opName, - bool isTableA, void (crund_ndb::Operations::*OP)(const NdbDictionary::Table*, int,int,bool), bool batch > -struct Driver::byPKOp : Op { - byPKOp() : Op(string(*opName) - + string(isTableA ? "AByPK" : "B0ByPK") +struct Driver::AByPKOp : Op { + AByPKOp() : Op(string(*opName) + (batch ? "_batch" : "")) { } virtual void run(int countA, int countB) const { - (ops->*OP)((isTableA ? ops->meta->table_A : ops->meta->table_B0), - 1, (isTableA ? countA : countB), batch); + (ops->*OP)(ops->meta->table_A, 1, countA, batch); + } +}; + +template< const char** opName, + void (crund_ndb::Operations::*OP)(const NdbDictionary::Table*, + int,int,bool), + bool batch > +struct Driver::B0ByPKOp : Op { + B0ByPKOp() : Op(string(*opName) + + (batch ? "_batch" : "")) { + } + + virtual void run(int countA, int countB) const { + (ops->*OP)(ops->meta->table_B0, 1, countB, batch); } }; @@ -668,10 +807,10 @@ template< const char** opName, void (crund_ndb::Operations::*OP)(const NdbDictionary::Table*, int,int,bool,int), bool batch > -struct Driver::lengthOp : Op { +struct Driver::LengthOp : Op { const int length; - lengthOp(int length) : Op(string(*opName) + LengthOp(int length) : Op(string(*opName) + toString(length) + (batch ? "_batch" : "")), length(length) { @@ -685,8 +824,8 @@ struct Driver::lengthOp : Op { template< const char** opName, void (crund_ndb::Operations::*OP)(int x,int y,bool z), bool forceSend > -struct Driver::relOp : Op { - relOp() : Op(string(*opName) + (forceSend ? "_forceSend" : "")) { +struct Driver::RelOp : Op { + RelOp() : Op(string(*opName) + (forceSend ? "_forceSend" : "")) { } virtual void run(int countA, int countB) const { @@ -700,15 +839,22 @@ struct Driver::relOp : Op { // // Until then, we have to allocate the operation names as variables // (which are external at file scope by default). -const char* del_s = "del"; -const char* set_s = "set"; -const char* get_s = "get"; +const char* delAByPK_s = "delAByPK"; +const char* delB0ByPK_s = "delB0ByPK"; +const char* setAByPK_s = "setAByPK"; +const char* setB0ByPK_s = "setB0ByPK"; +const char* getAByPK_bb_s = "getAByPK_bb"; +const char* getB0ByPK_bb_s = "getB0ByPK_bb"; +const char* getAByPK_ar_s = "getAByPK_ar"; +const char* getB0ByPK_ar_s = "getB0ByPK_ar"; + const char* setVarbinary_s = "setVarbinary"; const char* getVarbinary_s = "getVarbinary"; const char* clearVarbinary_s = "clearVarbinary"; const char* setVarchar_s = "setVarchar"; const char* getVarchar_s = "getVarchar"; const char* clearVarchar_s = "clearVarchar"; + const char* setB0ToA_s = "setB0->A"; const char* navB0ToA_s = "navB0->A"; const char* navB0ToAalt_s = "navB0->A_alt"; @@ -719,84 +865,92 @@ const char* nullB0ToA_s = "nullB0->A"; template< bool feat > void Driver::initOperationsFeat() { - const bool tableA = true; const bool setAttr = true; operations.push_back( - new InsOp< tableA, !setAttr, feat >()); + new AInsOp< !setAttr, feat >()); + + operations.push_back( + new B0InsOp< !setAttr, feat >()); operations.push_back( - new InsOp< !tableA, !setAttr, feat >()); + new AByPKOp< &setAByPK_s, &crund_ndb::Operations::setByPK, feat >()); operations.push_back( - new byPKOp< &set_s, tableA, &crund_ndb::Operations::setByPK, feat >()); + new B0ByPKOp< &setB0ByPK_s, &crund_ndb::Operations::setByPK, feat >()); operations.push_back( - new byPKOp< &set_s, !tableA, &crund_ndb::Operations::setByPK, feat >()); + new AByPKOp< &getAByPK_bb_s, &crund_ndb::Operations::getByPK_bb, feat >()); operations.push_back( - new byPKOp< &get_s, tableA, &crund_ndb::Operations::getByPK, feat >()); + new AByPKOp< &getAByPK_ar_s, &crund_ndb::Operations::getByPK_ar, feat >()); operations.push_back( - new byPKOp< &get_s, !tableA, &crund_ndb::Operations::getByPK, feat >()); + new B0ByPKOp< &getB0ByPK_bb_s, &crund_ndb::Operations::getByPK_bb, feat >()); - for (unsigned int i = 1; i <= maxStringLength; i *= 10) { + operations.push_back( + new B0ByPKOp< &getB0ByPK_ar_s, &crund_ndb::Operations::getByPK_ar, feat >()); + + for (int i = 1; i <= maxVarbinaryBytes; i *= 10) { const int length = i; operations.push_back( - new lengthOp< &setVarbinary_s, &crund_ndb::Operations::setVarbinary, feat >(length)); + new LengthOp< &setVarbinary_s, &crund_ndb::Operations::setVarbinary, feat >(length)); operations.push_back( - new lengthOp< &getVarbinary_s, &crund_ndb::Operations::getVarbinary, feat >(length)); + new LengthOp< &getVarbinary_s, &crund_ndb::Operations::getVarbinary, feat >(length)); operations.push_back( - new lengthOp< &clearVarbinary_s, &crund_ndb::Operations::setVarbinary, feat >(0)); + new LengthOp< &clearVarbinary_s, &crund_ndb::Operations::setVarbinary, feat >(0)); + } + + for (int i = 1; i <= maxVarcharChars; i *= 10) { + const int length = i; operations.push_back( - new lengthOp< &setVarchar_s, &crund_ndb::Operations::setVarchar, feat >(length)); + new LengthOp< &setVarchar_s, &crund_ndb::Operations::setVarchar, feat >(length)); operations.push_back( - new lengthOp< &getVarchar_s, &crund_ndb::Operations::getVarchar, feat >(length)); + new LengthOp< &getVarchar_s, &crund_ndb::Operations::getVarchar, feat >(length)); operations.push_back( - new lengthOp< &clearVarchar_s, &crund_ndb::Operations::setVarchar, feat >(0)); - + new LengthOp< &clearVarchar_s, &crund_ndb::Operations::setVarchar, feat >(0)); } operations.push_back( - new relOp< &setB0ToA_s, &crund_ndb::Operations::setB0ToA, feat >()); + new RelOp< &setB0ToA_s, &crund_ndb::Operations::setB0ToA, feat >()); operations.push_back( - new relOp< &navB0ToA_s, &crund_ndb::Operations::navB0ToA, feat >()); + new RelOp< &navB0ToA_s, &crund_ndb::Operations::navB0ToA, feat >()); operations.push_back( - new relOp< &navB0ToAalt_s, &crund_ndb::Operations::navB0ToAalt, feat >()); + new RelOp< &navB0ToAalt_s, &crund_ndb::Operations::navB0ToAalt, feat >()); operations.push_back( - new relOp< &navAToB0_s, &crund_ndb::Operations::navAToB0, feat >()); + new RelOp< &navAToB0_s, &crund_ndb::Operations::navAToB0, feat >()); operations.push_back( - new relOp< &navAToB0alt_s, &crund_ndb::Operations::navAToB0alt, feat >()); + new RelOp< &navAToB0alt_s, &crund_ndb::Operations::navAToB0alt, feat >()); operations.push_back( - new relOp< &nullB0ToA_s, &crund_ndb::Operations::nullB0ToA, feat >()); + new RelOp< &nullB0ToA_s, &crund_ndb::Operations::nullB0ToA, feat >()); operations.push_back( - new byPKOp< &del_s, !tableA, &crund_ndb::Operations::delByPK, feat >()); + new B0ByPKOp< &setAByPK_s, &crund_ndb::Operations::delByPK, feat >()); operations.push_back( - new byPKOp< &del_s, tableA, &crund_ndb::Operations::delByPK, feat >()); + new AByPKOp< &setB0ByPK_s, &crund_ndb::Operations::delByPK, feat >()); operations.push_back( - new InsOp< tableA, setAttr, feat >()); + new AInsOp< setAttr, feat >()); operations.push_back( - new InsOp< !tableA, setAttr, feat >()); + new B0InsOp< setAttr, feat >()); operations.push_back( - new DelAllOp< !tableA, feat >()); + new ADelAllOp< feat >()); operations.push_back( - new DelAllOp< tableA, feat >()); + new B0DelAllOp< feat >()); } void @@ -813,14 +967,7 @@ Driver::closeOperations() { void Driver::clearData() { - cout << "deleting all rows ..." << flush; - int delB0 = -1; - const bool batch = true; - ops->delByScan(ops->meta->table_B0, delB0, batch); - cout << " [B0: " << delB0 << flush; - int delA = -1; - ops->delByScan(ops->meta->table_A, delA, batch); - cout << ", A: " << delA << "]" << endl; + ops->clearData(); } //--------------------------------------------------------------------------- === modified file 'storage/ndb/test/crund/src/crundndb/Operations.cpp' --- a/storage/ndb/test/crund/src/crundndb/Operations.cpp 2010-09-29 10:02:15 +0000 +++ b/storage/ndb/test/crund/src/crundndb/Operations.cpp 2010-10-01 04:10:21 +0000 @@ -15,6 +15,7 @@ #include #include "helpers.hpp" +#include "string_helpers.hpp" #include "Operations.hpp" //using namespace std; @@ -26,6 +27,9 @@ using std::endl; using crund_ndb::Meta; using crund_ndb::Operations; +// JNI crashes with gcc & operator<<(ostream &, long/int) +using utils::toString; + /************************************************************ * Helper Macros & Functions ************************************************************/ @@ -35,8 +39,8 @@ using crund_ndb::Operations; // - all errors are reported and then followed by a process exit /* -// runtime/compiler bug? macro aborts during into->string conversion -#define ABORT_NDB_ERROR0(error) \ +// JNI crashes with gcc & operator<<(ostream &, long/int) +#define ABORT_NDB_ERROR0(error) \ do { cout << "!!! error in " << __FILE__ << ", line: " << __LINE__ \ << ", code: " << (int)error.code \ << ", msg: " << error.message << "." << endl; \ @@ -59,14 +63,6 @@ using crund_ndb::Operations; #define VERIFY(cond) \ if (cond); else ABORT_ERROR("wrong data; verification failed") -/* -static ostream& operator<<(ostream& s, const NdbError& e) -{ - s << "code: " << e.code << ", msg: " << e.message << "."; - return s; -} -*/ - /************************************************************ * Member Functions of Class Meta ************************************************************/ @@ -168,14 +164,17 @@ Operations::init(const char* mgmd_conn_s assert (mgmd_conn_str); // ndb_init must be called first - cout << "initializing NDBAPI..." << flush; + cout << endl + << "initializing NDBAPI ..." << flush; int stat = ndb_init(); if (stat != 0) ABORT_ERROR("ndb_init() returned: " << stat); - cout << " [ok]" << endl; + cout << " [ok]" << endl; // instantiate NDB cluster singleton + cout << "creating cluster conn ..." << flush; mgmd = new Ndb_cluster_connection(mgmd_conn_str); + cout << " [ok]" << endl; // no useful mgmd->string conversion // connect to cluster management node (ndb_mgmd) cout << "connecting to mgmd ..." << flush; @@ -219,10 +218,10 @@ Operations::initConnection(const char* c // connect to database cout << "connecting to database..." << flush; ndb = new Ndb(mgmd, catalog, schema); - //const int max_no_tx = 10; // maximum number of parallel tx (<=1024) + const int max_no_tx = 10; // maximum number of parallel tx (<=1024) // note each scan or index scan operation uses one extra transaction - //if (ndb->init(max_no_tx) != 0) - if (ndb->init() != 0) + //if (ndb->init() != 0) + if (ndb->init(max_no_tx) != 0) ABORT_NDB_ERROR(ndb->getNdbError()); cout << " [ok]" << endl; @@ -291,6 +290,19 @@ Operations::closeTransaction() // ---------------------------------------------------------------------- +void +Operations::clearData() +{ + cout << "deleting all rows ..." << flush; + const bool batch = true; + int delB0 = -1; + delByScan(meta->table_B0, delB0, batch); + cout << " [B0: " << toString(delB0) << flush; + int delA = -1; + delByScan(meta->table_A, delA, batch); + cout << ", A: " << toString(delA) << "]" << endl; +} + struct CommonAB { Int32 id; Int32 cint; @@ -439,7 +451,7 @@ Operations::delByScan(const NdbDictionar const bool forceSend_ = false; const bool releaseOp = false; op->close(forceSend_, releaseOp); - //CDBG << " deleted " << count << " rows" << endl; + //CDBG << "!!! deleted " << toString(count) << " rows" << endl; commitTransaction(); closeTransaction(); @@ -506,9 +518,9 @@ Operations::setByPK(const NdbDictionary: } void -Operations::getByPK(const NdbDictionary::Table* table, - int from, int to, - bool batch) +Operations::getByPK_bb(const NdbDictionary::Table* table, + int from, int to, + bool batch) { // allocate attributes holder const int count = (to - from) + 1; @@ -556,7 +568,7 @@ Operations::getByPK(const NdbDictionary: VERIFY(id == i); Int32 j = getCommonAB(pab); - //CDBG << "!!! id=" << id << ", i=" << i << endl; + //CDBG << "!!! id=" << toString(id) << ", i=" << toString(i) << endl; VERIFY(j == id); } @@ -564,7 +576,6 @@ Operations::getByPK(const NdbDictionary: delete[] ab; } -// XXX struct CommonAB_AR { NdbRecAttr* id; NdbRecAttr* cint; @@ -573,7 +584,6 @@ struct CommonAB_AR { NdbRecAttr* cdouble; }; -// XXX static inline Int32 getCommonAB(const CommonAB_AR* const ab) { @@ -587,7 +597,6 @@ getCommonAB(const CommonAB_AR* const ab) return cint; } -// XXX void Operations::getByPK_ar(const NdbDictionary::Table* table, int from, int to, @@ -639,7 +648,7 @@ Operations::getByPK_ar(const NdbDictiona VERIFY(id == i); Int32 j = getCommonAB(pab); - //CDBG << "!!! id=" << id << ", i=" << i << endl; + //CDBG << "!!! id=" << toString(id) << ", i=" << toString(i) << endl; VERIFY(j == id); } @@ -695,11 +704,9 @@ Operations::setVar(const NdbDictionary:: buf = new char[sbuf]; buf[0] = (char)slen; memcpy(buf + 1, str, slen); -#if 0 - CDBG << "!!! buf[0]=" << (int)buf[0] << endl; - CDBG << "!!! buf[1]=" << (int)buf[1] << endl; - CDBG << "!!! buf[" << slen << "]=" << (int)buf[slen] << endl; -#endif + //CDBG << "!!! buf[0]=" << toString(buf[0]) << endl; + //CDBG << "!!! buf[1]=" << toString(buf[1]) << endl; + //CDBG << "!!! buf[" << toString(slen) << "]=" << toString(buf[slen]) << endl; } beginTransaction(); @@ -743,13 +750,11 @@ Operations::getVar(const NdbDictionary:: const size_t sline = (1 + slen); const size_t sbuf = count * sline; char* const buf = new char[sbuf]; -#if 0 - memset(buf, 1, sbuf); - CDBG << "!!! buf[0]=" << (int)buf[0] << endl; - CDBG << "!!! buf[1]=" << (int)buf[1] << endl; - CDBG << "!!! buf[" << slen << "]=" << (int)buf[slen] << endl; - CDBG << "!!! buf[" << (slen+1) << "]=" << (int)buf[slen + 1] << endl; -#endif + //memset(buf, 1, sbuf); + //CDBG << "!!! buf[0]=" << toString(buf[0]) << endl; + //CDBG << "!!! buf[1]=" << toString(buf[1]) << endl; + //CDBG << "!!! buf[" << toString(slen) << "]=" << toString(buf[slen]) << endl; + //CDBG << "!!! buf[" << toString(slen+1) << "]=" << toString(buf[slen+1]) << endl; // fetch string attribute by key char* s = buf; @@ -781,12 +786,11 @@ Operations::getVar(const NdbDictionary:: // copy (move) the strings to make them aligned and 0-terminated s = buf; for (int i = from; i <= to; i++, s += sline) { -#if 0 - CDBG << "!!! s[0]=" << (int)s[0] << endl; - CDBG << "!!! s[1]=" << (int)s[1] << endl; - CDBG << "!!! s[" << slen << "]=" << (int)s[slen] << endl; - CDBG << "!!! s[" << (slen+1) << "]=" << (int)s[slen + 1] << endl; -#endif + //CDBG << "!!! s[0]=" << toString(s[0]) << endl; + //CDBG << "!!! s[1]=" << toString(s[1]) << endl; + //CDBG << "!!! s[" << toString(slen) << "]=" << toString(s[slen]) << endl; + //CDBG << "!!! s[" << toString(slen+1) << "]=" << toString(s[slen + 1]) << endl; + const size_t n = s[0]; VERIFY(n < sline); @@ -795,7 +799,6 @@ Operations::getVar(const NdbDictionary:: s[n] = 0; // check fetched values - //CDBG << "!!! s=" << (void*)s << ", '" << s << "'" << endl; VERIFY(strcmp(s, str) == 0); } assert (s == buf + sbuf); @@ -936,7 +939,7 @@ Operations::navB0ToA(int count_A, int co VERIFY(id == ((i - 1) % count_A) + 1); Int32 j = getCommonAB(pab); - //CDBG << "!!! id=" << id << ", i=" << i << endl; + //CDBG << "!!! id=" << toString(id) << ", i=" << toString(i) << endl; VERIFY(j == id); } @@ -1025,7 +1028,7 @@ Operations::navB0ToAalt(int count_A, int VERIFY(id == ((i - 1) % count_A) + 1); Int32 j = getCommonAB(pab); - //CDBG << "!!! id=" << id << ", i=" << i << endl; + //CDBG << "!!! id=" << toString(id) << ", i=" << toString(i) << endl; VERIFY(j == id); } @@ -1098,21 +1101,19 @@ Operations::navAToB0(int count_A, int co } commitTransaction(); closeTransaction(); - //CDBG << "!!! pab - ab =" << (pab-ab) << endl; + //CDBG << "!!! pab - ab =" << toString(pab-ab) << endl; assert (pab == ab + count_B); // check fetched values - // XXX this is may not be the most efficient way of testing... -// #ifndef NDEBUG + // XXX this is not the most efficient way of testing... vector b(ab, ab + count_B); sort(b.begin(), b.end(), compare); vector::const_iterator it = b.begin(); for (int i = 1; i <= count_B; i++, it++) { Int32 id = getCommonAB(&it[0]); - //CDBG << "!!! id=" << id << ", i=" << i << endl; + //CDBG << "!!! id=" << toString(id) << ", i=" << toString(i) << endl; VERIFY(id == i); } -//#endif // release attributes holder delete[] ab; @@ -1199,22 +1200,20 @@ Operations::navAToB0alt(int count_A, int } commitTransaction(); closeTransaction(); - //CDBG << "!!! a_id=" << a_id << ", pab - ab =" << (pab-ab) << endl; + //CDBG << "!!! pab - ab =" << toString(pab-ab) << endl; assert (a_id == count_A + 1); assert (pab == ab + count_B); // check fetched values - // XXX this is may not be the most efficient way of testing... -// #ifndef NDEBUG + // XXX this is not the most efficient way of testing... vector b(ab, ab + count_B); sort(b.begin(), b.end(), compare); vector::const_iterator it = b.begin(); for (int i = 1; i <= count_B; i++, it++) { Int32 id = getCommonAB(&it[0]); - //CDBG << "!!! id=" << id << ", i=" << i << endl; + //CDBG << "!!! id=" << toString(id) << ", i=" << toString(i) << endl; VERIFY(id == i); } -//#endif // release attributes holder delete[] ab; === modified file 'storage/ndb/test/crund/src/crundndb/Operations.hpp' --- a/storage/ndb/test/crund/src/crundndb/Operations.hpp 2010-02-14 05:05:31 +0000 +++ b/storage/ndb/test/crund/src/crundndb/Operations.hpp 2010-10-01 04:10:21 +0000 @@ -88,6 +88,8 @@ public: void rollbackTransaction(); + void clearData(); + void delByScan(const NdbDictionary::Table* table, int& count, bool batch); @@ -100,10 +102,9 @@ public: void setByPK(const NdbDictionary::Table* table, int from, int to, bool batch); - void getByPK(const NdbDictionary::Table* table, int from, int to, - bool batch); + void getByPK_bb(const NdbDictionary::Table* table, int from, int to, + bool batch); - // XXX void getByPK_ar(const NdbDictionary::Table* table, int from, int to, bool batch); === modified file 'storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp' --- a/storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp 2010-02-14 05:05:31 +0000 +++ b/storage/ndb/test/crund/src/crundndb/com_mysql_cluster_crund_NdbApiLoad.cpp 2010-10-01 04:10:21 +0000 @@ -4,7 +4,6 @@ */ #include -#include #include #include "com_mysql_cluster_crund_NdbApiLoad.h" @@ -93,13 +92,7 @@ Java_com_mysql_cluster_crund_NdbApiLoad_ jobject obj) { TRACE("clearData()"); - cout << "deleting all rows ..." << flush; - int delB0; - ops->delByScan(ops->meta->table_B0, delB0, true); - cout << " [B0: " << delB0 << flush; - int delA; - ops->delByScan(ops->meta->table_A, delA, true); - cout << ", A: " << delA << "]" << endl; + ops->clearData(); } JNIEXPORT void JNICALL @@ -223,25 +216,47 @@ Java_com_mysql_cluster_crund_NdbApiLoad_ } JNIEXPORT void JNICALL -Java_com_mysql_cluster_crund_NdbApiLoad_getAByPK(JNIEnv* env, - jobject obj, - jint count_A, - jint count_B, - jboolean batch) +Java_com_mysql_cluster_crund_NdbApiLoad_getAByPK_1bb(JNIEnv* env, + jobject obj, + jint count_A, + jint count_B, + jboolean batch) { - TRACE("getAByPK()"); - ops->getByPK(ops->meta->table_A, 1, count_A, batch == JNI_TRUE); + TRACE("getAByPK_bb()"); + ops->getByPK_bb(ops->meta->table_A, 1, count_A, batch == JNI_TRUE); } JNIEXPORT void JNICALL -Java_com_mysql_cluster_crund_NdbApiLoad_getB0ByPK(JNIEnv* env, - jobject obj, - jint count_A, - jint count_B, - jboolean batch) +Java_com_mysql_cluster_crund_NdbApiLoad_getB0ByPK_1bb(JNIEnv* env, + jobject obj, + jint count_A, + jint count_B, + jboolean batch) +{ + TRACE("getB0ByPK_bb()"); + ops->getByPK_bb(ops->meta->table_B0, 1, count_B, batch == JNI_TRUE); +} + +JNIEXPORT void JNICALL +Java_com_mysql_cluster_crund_NdbApiLoad_getAByPK_1ar(JNIEnv* env, + jobject obj, + jint count_A, + jint count_B, + jboolean batch) +{ + TRACE("getAByPK_ar()"); + ops->getByPK_ar(ops->meta->table_A, 1, count_A, batch == JNI_TRUE); +} + +JNIEXPORT void JNICALL +Java_com_mysql_cluster_crund_NdbApiLoad_getB0ByPK_1ar(JNIEnv* env, + jobject obj, + jint count_A, + jint count_B, + jboolean batch) { - TRACE("getB0ByPK()"); - ops->getByPK(ops->meta->table_B0, 1, count_B, batch == JNI_TRUE); + TRACE("getB0ByPK_ar()"); + ops->getByPK_ar(ops->meta->table_B0, 1, count_B, batch == JNI_TRUE); } JNIEXPORT void JNICALL --===============1988502458== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/martin.zaun@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: martin.zaun@stripped # target_branch: file:///Users/mz/mysql/ndb-7.1/ # testament_sha1: 28903fab21787ff38050fa2af2c2686d6f183993 # timestamp: 2010-09-30 22:11:59 -0700 # source_branch: file:///Users/mz/mysql/ndb-7.1-opt1/ # base_revision_id: jonas@stripped # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWWEEkBIAIpz/gH///UB7//// ///ffr////5gKn9569sNUx9vKJ7yIO67bNvZzp3fWlB1VF7rns3b3ZEs3bmsHN9we2ACj3saFdAd 3rClFrBVKo2xU5AdHTI7mB9avN7acw1vu5dbI2Niy0o1qjWprTaGtrQ0axCBoKUY0R6eqekyGj1D IaDTIBoDQxA0aAADQBowgJQIBBpAmpkmRPU9TTTTT1RgRhGQYCZPUYRgAgwIGmgCSUbUyh6h6mJo AZAADCDQAAAAAAAJNSIIBNAEMhPVPNU2KafqbRSeKPyRqeKZHpNNPQgND0m1MaT0BFIhGInoCaaN TNKn4myjEm0KZgmhqP0p5T1HqfqgAPSAA0MFSSBAEyMgBGmmkyaNEzQQxEB+qb1U0YZRoMgDNQeU 5x5FAopAlFUUgk1Got8Ff2T0d383ZRXoZpt95s2QogKR95r03qB6bhjobLVekrRf06O7J/qJNMO5 NLSU9r5rVPqQ+bbXE/W9wp/vIuMO4XtmZ2+2G1MNxrs3Z7Ow2IgsRW2w+e966r9znXDaGF8m2DpV 3pTvafr/ifyOfj8G579+qvB0dLeuqsMDyqbIMTYZfIiDMAyTaynXqiSVCxSW6uOy1WQQTyitGFpw Kp5cMonZwpCKUC4o3FEH8uGq1SBkUFM3IBilx06qPCXMcoeAmz41tkQskz0EqTv8fiLl+R1kTjeB 0K6uOgsrbw6IeO2RhdksMoQQn9kM0kuS5cd2qmqrTWtpwRSH/nF4z9x+EMgLBMjImgRKk1k1y9ru tWdGcnUKaqVrOyMeKGthrRW4YSsyZT4k0JuddsAJq5ODm/ZbsPm4DUgbWS5w1p5OmxVC1alWoeJ2 jydfco+UePH0tXWniX1T/bVSNdySAF1JqFF2QpkhqSyGxCanYITFDHKjJKZDN2uTNTIZ6aJi5MxY Xz55LSQwtAyVERwtnpuILiGbRgNVbF1E1tGNgaFy8W6m6LFSuYzxOMZl20Ik4qzE41rBLlUYgzpg 8VpYoThNuYEiBJNstEurs537RCjTOEqGhBz/g5JHFFluMoXGBqSaIqDUOjskCoyIDRImSMSrkIAo KUkqAgSaqCgRCftTqsshSURooxoO7RGFJGdRJf/JZk0Pg/jR3SbKnbpfBhEWg8LEx/YthKmVSWUt aUAMEEKqFpIzUMsKCAj7jDuLz9ppP3mDSRSGrHO/h/mnJSVsJSzQXW+pGTtxwYIp02nGP9D97+5k xrt1P73u7Suyz89QYdWa1rXMFSb5vfvZOhxdbK3vk8tdq9DBDR3Ie1ARSALIqiISLILFCCiixYCw WRYAq5w6hDVIZ1DnIAdno+7oiPke2e/8DVf2NOVbey6eMFzOQPYHCIUS5RcNkkCjEh4KbmUcoseA zQ3sIIogmjwb10ZuWtVwydGCMnVaoSCYLQtOt6bc6kXkFqJBZzKw4JVYot7QOklqXYuuE9fMCaIG FoaNTV5WhMau1IyG4bPdQoo1WgVF3jDxhS8sOlNKvgN0aFS82dmvV8XlJbrottL3jAbASElajNi1 TDaYh1hkeqarzc9kkW1sKIUhzIF6bRaVAgoj4FkjCinCtMusgMDL3dxd1gvRZxJE3DjDjqHMEatZ sqxSzBNqGl2GFNINWwMFqqpcgYc0rFLIxgVSzeg6yr1RVyi6UFlAJouRhDIcuSrOrPcTOo1hL2qr DUBJpjFdggP/g7R0OKincdhsLjD/gRRLeKyWegI49d1hYDrQNYRCxKlaqtBZqLC1Zioiq/RUY0Qx alPJZ0+Zomga2zhdkUe8rF0oGmXWBTQ+oQYijszMzMzVE92dj3TkjhiJ5UmYbjIMJCez3dW8TMJs 69OfsBVFBapcn23C5evfYYzyOhlknNLJ7hclDQucRsjUseY2Ln/J/2u0ZF/r9/5OBZ/vMwRL8Q48 ic3Jo6PAskP+DpvgaCxa1i0iUrjjyJzcmCuPA4Bw3BgaQWgYwOUzpcapUOWT9UmvViTJg5qmDvZj uS7HQzM7FrvvklXr1yfSqMIClYCCAg5DWFWU5sFt+/qlKWOZ6G/WqNIXXE0SHUY6ZDJkUmJr8uRE YwbdBiT+P8zadIc25VV6O/gZn4AlAbqDnL2JyE3adOltjRMQBbCgvnHB2k/0+OhqFTsedkX1mmqX CY/FBmYZmOHdx19Ckt6NubGl/o9xA5BoesXXkaU1MtuGzXOdwNfIec/Bq6Gb0cqG9NzO8DctyOLJ I5bDdsohqGu3cspyoQXH11r0dvUFS5Q2NgQOBtKvkj95sf0UXeczboCbIIhcYq/c9yx6+VrqXtTR dbOc5/5cwVD6E4rxcQaDFhMYaik518UQsAUIa2hCI0yCyHHau+BDoCHnky6v0fR+sCqKqSg4/LeO /0DNBuU+x5F3UaaRGKBlQEV+DMRp4pbNLbo+bC+Hy4Xax1Hafg9LIcW/gqqUN3YfDz7rdMgqGGb7 z8x+XTS2rDAh9iWgaM+fd0e3HvfVTRepp9tM67F6g7IdLwG0MURNorTtL+wgeC2Oj4s9259Ozhts w0PDtCH5owDy0sqE6/neCmpJbp6rKz3gqyWPJ2VGM8BIDQwp8zxCt7iss7O/FMpHc/JfDMQFqyiF VVQFJNe3bVV4glFWW4Qxx/MKNmi1UKNmhqwjKKqBVNBCqUSoVSKKLRYsWBtCFikUUbS0RKpi0JQl SxVAb5QwEQHd6woPYIBL+UU/R3Fz8+YT55CbA+LlMSxLcAsV90orYW/Iqqw586SB78TRLL807H90 HnPg+sCD6bNBiq2YZSFTSsgzN1tK0TYyLCOEljrD3L4GCY4jQWPuUMCWRCJKsCGVS4LIUSrE2YHG U6mPRO1Ive9/jDPVFVVVVVVV0Fb0KjDWBRbRvkbV5cM/cdRVH/qXMw9xj6bUoMElSfxgTuJ73wcg t/o5lZQszYbqn5SaP6w724cBJjMb7O3ZVVgghe971VXwxgguUP3k3gUwZA3gmIniBhlIGCH0S2Mu V1tN617KOly8FW0Zzq9fBbNW2EVQWcVCSdWg78pJRRdufzGZrvZcsZw3MSRO7c0zDr5pmxy+E7/1 KZP4lFryzY+MsWMWEn6hylYfE/dSEHxk/XKSeyjs+PxopAlKRkhAIOYNY9cvnFvUp8Vec5yn7nod S5cuXPP5yPR4+jxwtTYPMZlRE7LBxiJoqpKxp81XLWtbYZiZ1kORcPIXL4ayliRrr8/x0rVXtRow uVb1iusiaIiiVBBfRtcDTlwXG2ZbbZCG4xEbUypnLdQKaq+AeG3PWOVZZWXVddic37XwO5tkwfSl iz9CbTdPuTeo7TB1utMZGK56XFrYwFzU2JTYU0FT8cSbRC/A0Ik2HQgYCE6Tg0BPp4l+Qbxh7ijD sMpNRKd8l5yHWd07qr7j8BwGrJNB7io6GuRjtaOTvrZVc5mTJy2zJLjySoJpbbVYUOn/npvAhKtA UUYeFwxUEIPbKHtmg5bZ5sMLFjSQmWnLT6OmjOQA9E+GB2fMqjOg/FUaqqSlFFU13IYEd3Vfx7PZ l8JGbW2GTe5XLjllrvQta++VSpWlrD9fa+fw813h4fLf44Ko+N+GWXIEDTVQUDUgZoBoqiGhlN0M kCyBKZMEUIU46KIYIoGTZLYVA0sBYFMMHUl8DK59mBVypPYMhqC8BCuygMFKURUiGlKhI4qiXVUc n5eZtYN27fcRL4kkpezSSLM6/kXUXp71y+/HfeSGMIAjOI12LRMkduu1wUzE1ZlznEJqCIewZACZ bEtHd5CKEjAkOWNhoUkRsUhKJEhwcWqqqbkoLIswRigVJc3EQqhzyLWL4ifFLy2T2b2le3MGDFra C/c5ubZmXGTJaFhcUfnLxhPeieIPGGeuchR8MKbkLZAbLqqJRe69mYGyMhOc5MuSZ3rSbQUtWZDV m1HLPN1mhGIX+E1ELDCYwhoJqkId/VK8OMNCDsvrNHKYmYh4O1VVVVRWhpbEglzCjQBBAMCQ2YWR NVIDeo1TyqJm6bTizGqKoyq0hBENJcvamchVnM94O9bed49haCLZdN1BlTAqyBT08yWxsULmpsbH gbFctUTVbwwHpMsnQ1xnGFjbvCnKWuixt39ODmMcZCfJrNHmjRObI7CJP4+uZtdW0wyOiIHMRCwU L9HnyQQuFxz0HYsSlsvPVLCaKghjsmjlBfAYcKXszr0FGigph4UpYST1FQYXQYsMOjrXtsa961PL luZU6awXLty/Ytc4r8G5JTnXTOhXf2JysXWo/g3tri4r2nsus6lM21ZndPb0amc1m+Buu6eLWVhJ DHUFdDMMGoIi04tubTV3Kh1rEq6gZl20YWx8iK7Xi3bgBaIic5RbbKRxoIiJ5rzXyZjVtlpZ87og g0td99tdCoggsGgya+1fCmik1SSlUQSjdV38DwRESUELd8uhMkMcTs6Nu2NW26FFVyhv15OiCX6E wPNDGnkXIj/5HGV2isDpwaDDos9eEc1VxzqOT59HpPxH6rMXK0FSQqXEXGp7U0RCAsUO1wkMOKdy pA5cwFRaXFoElXK/IPW9aJk3s25WkolGSFlZOJDgiuWros8MBVq99wGuBN9iM1dzqqtNUdHZWGCB sMLZIQiLCSTgbBPAo5Ubr46koTpr4Oaqr6Co+T7I2VV9B9hbypoplnSSi02wbEGNTcbuelEEILzO R6CH3XZvI6RWshEdNFGKHibnQyaFSZcKHQqTMFTU8jqSKGCpzODBcqeAmDim3HpNpJnic7yCTsct L2pNlKVKxBK0Vk8TrKIzEq0umi1sLIuq4VkRA56gwiGkXRBDg5j40bZbqxqXDamJIiJNPCQxRUjO 44ehbmo2mCoz8YIfIpMgdERKikDTURDY23Jd130aavW49BeCGFuGj9ew7lUREXnSh8QRcizJ4NTA 8C6lhau6KcjW4aIDAhL1bmBShb2CYkXO2DaTm6Iiad77klM2ZCas6juKtY7F3xza6yu1iGrBQNim YXKg7MyONsZEkI+2LSwgQNwgyBEIgS6IhXt26iJzJ4uGVcWi8EkmXuabUYBxtzzExh1aRMiWofKT B0LTDgwMmOhRsxE4gOCZMtAdifF69QyW7r0UoQczELdi6pM6HZOCi8p0Kv4NyU3NzeuZsWxr1smm 5spt0thonviOE4TdIQ6JnMkXleIDe7XY7arTm2XftyrNKxzvk4klWuXexEVk1ZXw0gY8XqQXEa6k L2csacjYevYesIs9zoD7Iw0iuh7sVdl841UU81Bk2MjyWsNES5HDGXIeaYpEF9yT7lQm4LknIjjB erYyanU4xGJmXuRwXOpyNCmTTk39eXW2SIefjGO7X6azQkzTXMMMZld1pYrNRWlVbVaVa0LWfeLW DTAURKJ1FW1lZZLoHQ1HuLKVliNLDYIozyKEyRA+ow+tDjiZK7FL6VNKSlPQhERI3LNqK4tgil3K UuvUcYzo17wo2hJypDjjM8yZndScXXzpHK0udTMspzuVTaualqvbz0+CCHqE95OXOfXrB4ZZOu/I eUmnKWXKTlvdWcfD3pjqWt5sREFrFY87YZynMA4MHGFeIYFtmExTBzKZKlCCxe+t6kikitGJmLmJ SWfS5c3IlMq7aLo3modSdhzjdXkSPLQscjR21UYWhncoZJ9yhM8DUmLzQyMaF2FFe/Q8BMG5QqHt ponYfpc6VZYZ0kIiorZi2so61m0sznRVnMiCcXtnOj3aY5BFYZSWGs1g0SxoTxiJJqMXVVS1BRKk 93TU6FXOhmscypmsYXQYgjqYDgkbnQNEzhTgc1JmNHwVzsSXPOi0kXOoch5HbyjqbTccqazYk9w5 zUTf0wfCtVS6wsUWFGvg4uEF1BityF85+VZF53ydAle5LrUkrNqmhEq14CFW+G+QyNBQSJkjfJrL AZhhDJJZcRecLrGSyRTBV0mJG2SM2dS8PfO93/ghDn80Kh2CF3iopMZjTaYzs71iYCiIxY5VTH+6 FFRTzabTQy8OErmQlqu5xSrk7rn/2Bq6LN7XlJjD28mnmlN3XXe0TXaGVkCoxUBhRUKHI7+OC3xY BxyZFAsdOm2lrXGZqXl658XB8QSiPMktKUU3CUEksJLDdksMkhe5QJIH1ICj+tqEigf+q0yEJ+cI wOMEh8L7QgzLWWUn3SxLv63+D7FKvj9apJYrYXLRYssWEsMCej1InHVInRJ4yXJgWDnNpyFMUFFF BFQGTCmQSISqpTpIDJSCB9R3tbYywVNED9wXh4Ty+2QwGRgHGyJ9qpUXqgWg0JrkDQeel1lvxRa1 oCNjIA8d75xiqh6fqoSaJRD9IU00mec5vQ9pwTSf+3P/BtjYj7xtBuSpON/LS+Kpjy4r63b98LQh dl73Kqpe+0qqMp0TySRYxSRVMSbpIeL0FcHHpCe0h6j7+aN9o2tFVRiKqoiI0DSiIiNFUtA0oqIq o2DL4lVVEVVT9n6dc8YQyD7TmPtE19qqqiKirw/h7A/JmH/+idYQf5H3Q/5NQbONVVVXBPlbR2v9 fPWs1Hsd9/e57GR0z2Fx0BtioxEVVVVERiLcNhzc3VId/Z7CO/jtP+xuPzGfPq81dp5Wd09OCu9i jTJqWNnUqiu8mRJ0/5a5KnwBQc/BcNvaMJPEIEnBPOBMzlNsxETz8mEmr1G9I+/EXt8M5gQ8ul1+ u9pmP0oZ/0il2eUVglZOV/A+j7Up8vRPT1fr+ns9dVTtJEosVe4FFy5e1iiwJaFA0K5rw2OB30VQ ez9nypl5p9aRH/mXvBp993tOpx5rzoFJhDw8H3NIG7V1CKisYrO8ZndDt91VVRFVVVWIoqqqq8Qe MtZVVRERFVVVVFVFVBiqQRERZ6jpVSRdG3M5gwPLhIyBuhTyEN5DOOUn2o8vD3DuNTNGk0vLBx+z VNUirVVFpFWeHxHBE4zNPGeRfJRSPDRSJYn2UBMCxAf01e1XwjYPt1ez5fk/20TLgA6wLHYQPppR VlyqJPk9SPVS1Vgn4/y2MC8qqO4Mw0giJGToeT22wV1KL9kU95RgkZ31wnQ6/m78CVbk9eFVVVVV mQnhk9wMpM9gecOHikEQYHMJKlSR4yYCeLk3a2ndVWLLPntu08apiwYNkmBD+186zZVd1LLKU/mN NxZFRNTkeT4v7XnK8hEFUQO/3z75MzB4/LqWLjFvUajDHw/CKmTYgYK2KzP90kbnAwx/Z1Q/xPx/ RX19EkJ/msxZTWbmMqKUxpiqmGNY4zBJi6o2crxcza5nI/byNL4LODMYu3M9iWkjsdqmbGE8IiWU 8mx4SYsXIuS5+4uO1Xu7WpyTjmZNUa5I1nj7J8bOpcWpsMf9yYS7WE+EdWNcXt9Ss0ZofHTSKQzM m2TCSaS9oUudEc6cJ7L+FvxVR2qLUolKlKkXiyWjsf1RCkRxf0oviLk/VuSSdLGQL5JOU5KI3ZrJ u+2jA9Zta8QjBxB7gjQXwUPIjSVFYq2hCZjWv4vXIGEP8En9Ec00RI6HL1m0KUbhZU9Dsep6vkJz PqnyuhpMlzBg0vY9b6ly49JrXNv0fX9DBiwdi5lyK1sIG5FJ4n1K8fqr07ZeTuyrIccnKxlGCJkm IiY4mOMwARhicyXbuLgXXXml6ITYtG29fGiJsJYlpIqQ3KJiUmDnXRpc3M/rZ3dNTodTX6UNPQEJ Ui9aVp7z+siIP/fXI/0EOwNRwEx2uo5urG4jx8N9gggghjhPCPMGUVEsTiw99V1m0o0m/fe+R6W9 l3Mss7vZ+5Kcng0rmtZ63natD63q8nI/vI7FJJh16G5+k27XNzcF6nc8vyZ3Fwc7pdxIdjt9vt1O YlQU/T0MmTr4IllRExnNX+1x/Oq+PsntRVngOyCuetEweY7EwwgIH27FAcwPJoHsJr7ALhylrlgG ICIgwJKhZhH3ypWclzQIZmgSFoZhvCGq6wVVa5naFRm9KWkjeqlcUs51w4L5axY+i0haXSWWWqKQ olu+nxo6Ck9eCY3JlbPJ6+pY6dTV6Wpk8fQvaVlz0MWuSTxbWzS2NEiMYjYkZWfIybF95k9KyZtB ItLSjdVIVGBQngs0OHF0KxkevgsJ+AaFlqbylKLU9TBwZL2o0uC91tynpTMsmK5gZISeBMSQbpmD Q0PEEoZAVpmqDJ0YYwREeEwAgwiTNJJQ1U8tNVZzvT1Jz9WdPNS1yxMl/uYGXCGGFpTzh5Zjj4mE suYUEQQ1CWsVES0umfG9Dg3vDP3/b3dDF7nQ6nyY+Cy9q2aNtn8ikvavANU7czZYxPL5Q7YQTxFi jaZckDmO/S5tMjYj5hCYhMTcTO6SBKoYgJTrHggKnfLCsZqslTXzXHbrIzcYfCEKxHEIyOIk5Hne y3me8rjJFO8WGjmqwX2x0ocjrbeJ5Gp6hj1bMRPgHMHkKgofHPtI+OOgvI5bei5jZjD1d8mGFfUB Cm+hBh4zuLleMoPooJI0UY9hCUVK5n3LJjjJE7WMP7IYGleR7UpIqDm6o+Wa2KurkMkyLmRgJwbM AzNVJMSFpEAvyHyllJ1waq76zPXWsxTNlLQKOUjeDwgYSYBjJQdFoFFBRzQ6zOhnEoQSRRCCRVER VEIqIqKqxVwhMlrx2fOl8RcJlEMXofWfZxH86RrSHvMm0kslPG35mFPrfS6nse5f87P7lO9Zk9Dn YMGD3vSzNBZxaH0tLJoe5TC+amtlqW/u3JNrY1ud66muMzc1Lm5r99zQ5GojQiYsjffc0mI0AmK0 qNS/AQm2moQgE9ITkZYGry9ERUxW9v4YzgzWdui98J5nqkmuLUUoQsVxiCUSwoyoKVJEOKTQHIEm j49h78+rH9WFfiwSGiFhZEpMODDo7OC6hPOG9HUKOFwiwTod8HCoVciJ6hpxKmQcxrdpCDAwDBOS SVQPzRGU/FgmEKhMKEVIP3RG+18O7dxcfvqzFnMlnb358miPN7uCM68vQFAXxhJmY+6yetRKEJgd dAUHmhJ85pPSPKkmonQaichIHtLGuHrTlGScnKqqqqwiN6JERFZ1Aly6ewQ2dJQofrAhUhgQnK6G qNey0jz6rMvvWkDMfYh3t7L9ckYdk7/yOLT1IlM3nUYGGCmBCShkUPQbevYmkuUWDoYveOqSVJPK Bcr52rkKGqVVAXSOU+YwUvXyF2/6nyNjc3FFURUiKqRMzi/UlvyUsJ4minPPcsljZczlg8DrakM0 aE6T7mSYT2k4PzvuZHeuXKU+/0S5M3B0Dke8olaWHmDZcQg9OUnPjCKE3HpVOIx6Ce6VIQ+8c4me YgjIM4U12KDtZPVYhdO6BgBrAlygM5CZJIoClWZIoIkYooyJbRjJ0Qmg5pJMAhQCMikoUnMLG6Il SFxLhS0tEpBgVoUk14BLDfI5QptXCcCJlUTQYU0m2duJMxEcp7yTAEy2ZxiG4TPaKUmN25MEpzJS XOPkg3StddqScJaQwUkqhJpyrJG+TSisVdMIWeTrnRMGDXtzZr5L7L+O6tvqeJevkEgUCVXuiSeO GWj0cuRZS7e9yyl297ywXb3vLQu7J2n3z2yEKDeE3JASYm2tgnbDRUUxXMZ31f8xzFzFmI5olpK7 lbyYTMekYlBFuYTSon/x2nfXct5i/oILkKYCyCclc84YSMmK9esuS5iwgqQKWmKkLSBfJZpmBZdq QuLkpJSWP07/0VVVEelrtKytO1CghGdBEhgYJhiVaVSYS6QXGZvds3iXuq6q2Ll12TQJKSaDxc0d m9k6Eml0J+x/EvS/Uyk0xEUUSyHyNK6S6Uvk1seRrQs92BgmXVYzLwWUhGLJR/mQ5i5JLXGEIYmB KioRC0oXLrpILIXRFJVJGbj02mZh0GMlkrLETvaOIx6ZFvgGPODNVaT1PGEDApSHkI1au4vTbjDI VJ4RJ+KX5oikqDMzEExqhYO0mtYQeBiKVVkAHB4hQv/sC49jr+ZdzsVjo8qrCQ9CXmCR6l69RSyP VPLCE8snY70WvuqKPZESpIvdyH0LRzRHvwSyc7ph8zabuGl9JNkkd3WkJhlwOFLI8lUU5GtD5QDf IwlmBRDzhuOE8ckmCDYPYjw6W1VlY8iyFJFJ/PJJ8k++SOAEhsH2XDhmRfJDKCIUYUYDEsCnRPuF MXc0EW6XTKUUmCdjm8TspE2KkZTk0APCqYlHJADWRoIMVx4Q+/gQfE7WsdL53nNYBuvodaiXA8mU yNRAQQUQRJ+4SkVEZaoFgYSwow4S8DrHSIfAkMoYwSSwskRghU55bPXlLSLQvirVAQIYpnWkOD8k 7jPDMxQuYoiuxR275Z7ObvfOUAl3lwqIcyp3fvfIRBAlQ3GI41EhJCcaEkSvSW2qnbCDwjCptLgw IWgVkqCgqSgBnnYVCREIjCF6kDktCBq9iX5IYyNy3TCT6WaSS6ZlilUojXn5wTkoqyxN4FqsNDS1 10eYywn2G6yGgvmaqDO9SS7ZalUtGjqw1BCqwBOGZSHGQmczMaREMb2gTB/t3E675YU1SPksQmkZ e41m1YVom4iE5DYqYgSjSbsDaf7983yaJyx7TcLm03BuGQXFlfHhWqrRgN7s+mf0H8JRG6QFVRWB qcrwsJEt9dFYaCScxNwAYQ86LCcpDlNe1jOR2iVih1zc0vNSqQ/HRFHh8T7gDAYA1Fy9mtQxkKU0 nVu1latBmVOw4c5Gk9B36Ma9LmFnO2VmbXNgqnzCzb+KTsbvsmTpeXzZl5KToQ5oIwgwLiGBchHC ScZKsLRKRFKJUpJguLNqnlSYDNmS6HJZmuuVhUF8mbHFdMqYLFCyl8R9pPVeYqYVGNlk/eNSxcSY RCokqImSK1EqSMRqYJJmYkMtOvQM8SrNQN5d+EoLj4CrfGYKEyEbC5UspVMJnycHEpSlZuEkl7J5 1ondEciQ3tPa5koL5H1ODe34lz7oqScYyS3UVEHDMy5Nrks6VUpMEDah0tJwqqJq57RItkyhpkhm TwmosRDIqQ6FEighAWAsoYXpYL2bGcOT+pMyRyN2p+KMUuho8PMleOnPTukjKZBknPUAYlYNih7j YHWOCgyvmmZU3ujfqaC1SkX8ciRNQCQKzFNYKF4Smo0DkQzuNcqDwveJq2IDugaW8ZjaotRNUR5N 5J+f05id5klBYs9aZhPJpkR+E3z9qmaZKKVI52aQb1oha1fPsx3spMil9e/G75L08yeMiOaaTRqM +SlPweedoz19qvJOg1Ej4tcdB86fguFYuuIywelA6G8Ctcyki2GIFO8IpDhHMBRpA7YXaXkSxtRN jb4FAMQhTCWEjQrxRARERAC/ZBLhjWhKQSggCS8pIfW+uS0exoqT7RdyRThQkGEEkBI= --===============1988502458==--