Browse Source

HPCC-12251 Create cassandra plugin for workunit storage

Fixed issues with secondary table workunitsByOwner
Added unit tests
Added delete support
Various minor fixes

Renamed misleading parameter in some workunit.?pp functions

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 10 years ago
parent
commit
3d3027a471

+ 11 - 9
common/workunit/workunit.cpp

@@ -2199,19 +2199,19 @@ CWorkUnitFactory::~CWorkUnitFactory()
 {
 }
 
-IWorkUnit* CWorkUnitFactory::createNamedWorkUnit(const char *wuid, const char *app, const char *user, ISecManager *secmgr, ISecUser *secuser)
+IWorkUnit* CWorkUnitFactory::createNamedWorkUnit(const char *wuid, const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
 {
-    checkWuScopeSecAccess(user, secmgr, secuser, SecAccess_Write, "Create", true, true);
+    checkWuScopeSecAccess(scope, secmgr, secuser, SecAccess_Write, "Create", true, true);
     Owned<CLocalWorkUnit> cw = _createWorkUnit(wuid, secmgr, secuser);
-    if (user)
-        cw->setWuScope(user);  // Note - this may check access rights and throw exception. Is that correct? We might prefer to only check access once, and this will check on the lock too...
+    if (scope)
+        cw->setWuScope(scope);  // Note - this may check access rights and throw exception. Is that correct? We might prefer to only check access once, and this will check on the lock too...
     IWorkUnit* ret = &cw->lockRemote(false);   // Note - this may throw exception if user does not have rights.
     ret->setDebugValue("CREATED_BY", app, true);
-    ret->setDebugValue("CREATED_FOR", user, true);
+    ret->setDebugValue("CREATED_FOR", scope, true);
     return ret;
 }
 
-IWorkUnit* CWorkUnitFactory::createWorkUnit(const char *app, const char *user, ISecManager *secmgr, ISecUser *secuser)
+IWorkUnit* CWorkUnitFactory::createWorkUnit(const char *app, const char *scope, ISecManager *secmgr, ISecUser *secuser)
 {
     StringBuffer wuid("W");
     char result[32];
@@ -2222,7 +2222,7 @@ IWorkUnit* CWorkUnitFactory::createWorkUnit(const char *app, const char *user, I
     wuid.append(result);
     if (workUnitTraceLevel > 1)
         PrintLog("createWorkUnit created %s", wuid.str());
-    IWorkUnit* ret = createNamedWorkUnit(wuid.str(), app, user, secmgr, secuser);
+    IWorkUnit* ret = createNamedWorkUnit(wuid.str(), app, scope, secmgr, secuser);
     if (workUnitTraceLevel > 1)
         PrintLog("createWorkUnit created %s", ret->queryWuid());
     addTimeStamp(ret, SSTglobal, NULL, StWhenCreated);
@@ -2990,9 +2990,11 @@ extern WORKUNIT_API IWorkUnitFactory * getWorkUnitFactory()
         CriticalBlock b(factoryCrit);
         if (!factory)   // NOTE - this "double test" paradigm is not guaranteed threadsafe on modern systems/compilers - I think in this instance that is harmless even in the (extremely) unlikely event that it resulted in the setown being called twice.
         {
+            const char *forceEnv = getenv("FORCE_DALI_WORKUNITS");
+            bool forceDali = forceEnv && !strieq(forceEnv, "off") && !strieq(forceEnv, "0");
             Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software/WorkUnitsServer", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
             // MORE - arguably should be looking in the config section that corresponds to the dali we connected to. If you want to allow some dalis to be configured to use a WU server and others not.
-            if (conn)
+            if (conn && !forceDali)
             {
                 const IPropertyTree *ptree = conn->queryRoot();
                 const char *pluginName = ptree->queryProp("@plugin");
@@ -3291,7 +3293,7 @@ void CLocalWorkUnit::beforeDispose()
 
 void CLocalWorkUnit::cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
 {
-    TIME_SECTION("WUDELETE cleanupAndDelete total");
+    MTIME_SECTION(queryActiveTimer(), "WUDELETE cleanupAndDelete total");
     // Delete any related things in SDS etc that might otherwise be forgotten
     if (p->getPropBool("@protected", false))
         throw MakeStringException(WUERR_WorkunitProtected, "%s: Workunit is protected",p->queryName());

+ 2 - 2
common/workunit/workunit.hpp

@@ -1258,13 +1258,13 @@ typedef IIteratorOf<IPropertyTree> IConstQuerySetQueryIterator;
 
 interface IWorkUnitFactory : extends IInterface
 {
-    virtual IWorkUnit *createWorkUnit(const char *app, const char *user, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
+    virtual IWorkUnit *createWorkUnit(const char *app, const char *scope, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual bool deleteWorkUnit(const char *wuid, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual IConstWorkUnit * openWorkUnit(const char *wuid, bool lock, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual IConstWorkUnitIterator * getWorkUnitsByOwner(const char * owner, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual IWorkUnit * updateWorkUnit(const char * wuid, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual int setTracingLevel(int newlevel) = 0;
-    virtual IWorkUnit * createNamedWorkUnit(const char * wuid, const char * app, const char * user, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
+    virtual IWorkUnit * createNamedWorkUnit(const char * wuid, const char * app, const char * scope, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual IWorkUnit * getGlobalWorkUnit(ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual IConstWorkUnitIterator * getWorkUnitsByState(WUState state, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;
     virtual IConstWorkUnitIterator * getWorkUnitsByECL(const char * ecl, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;

+ 1 - 1
common/workunit/workunit.ipp

@@ -578,7 +578,7 @@ public:
     virtual IConstWorkUnit * openWorkUnit(const char * wuid, bool lock, ISecManager *secmgr, ISecUser *secuser);
     virtual IWorkUnit * updateWorkUnit(const char * wuid, ISecManager *secmgr, ISecUser *secuser);
     virtual int setTracingLevel(int newlevel);
-    virtual IWorkUnit * createNamedWorkUnit(const char * wuid, const char * app, const char * user, ISecManager *secmgr, ISecUser *secuser);
+    virtual IWorkUnit * createNamedWorkUnit(const char * wuid, const char * app, const char *scope, ISecManager *secmgr, ISecUser *secuser);
     virtual IWorkUnit * getGlobalWorkUnit(ISecManager *secmgr, ISecUser *secuser) = 0;
     virtual IConstWorkUnitIterator * getWorkUnitsByOwner(const char * owner, ISecManager *secmgr, ISecUser *secuser) = 0;
     virtual IConstWorkUnitIterator * getWorkUnitsByState(WUState state, ISecManager *secmgr = NULL, ISecUser *secuser = NULL) = 0;

+ 2 - 0
ecl/wutest/CMakeLists.txt

@@ -36,6 +36,7 @@ include_directories (
          ./../../system/jlib 
          ./../../common/environment 
          ./../../common/workunit 
+         ./../../testing/unittests 
     )
 
 ADD_DEFINITIONS( -D_CONSOLE )
@@ -55,6 +56,7 @@ target_link_libraries ( wutest
          eclrtl 
          deftype
          workunit 
+         ${CPPUNIT_LIBRARIES}
     )
     
 if ( FORCE_WORKUNITS_TO_CASSANDRA )

+ 77 - 3
ecl/wutest/wutest.cpp

@@ -29,6 +29,11 @@
 #include "danqs.hpp"
 #include "dalienv.hpp"
 
+#ifdef _USE_CPPUNIT
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#endif
+
 void usage()
 {
     printf("Usage: WUTEST action [WUID=xxx] [OWNER=xxx]\n\n"
@@ -172,8 +177,9 @@ int main(int argc, const char *argv[])
     if (globals->getProp("CASSANDRASERVER", cassandraServer))
     {
         // Statically linking to cassandra plugin makes debugging easier (and means can debug simple cassandra workunit interactions without needing dali running)
-        Owned<IPTree> props = createPTreeFromXMLString("<WorkUnitsServer><Option name='server' value='.'/></WorkUnitsServer>");
+        Owned<IPTree> props = createPTreeFromXMLString("<WorkUnitsServer><Option name='server' value='.'/><Option name='randomWuidSuffix' value='4'/><Option name='traceLevel' value='0'/></WorkUnitsServer>");
         props->setProp("Option[@name='server']/@value", cassandraServer.str());
+        props->setPropInt("Option[@name='traceLevel']/@value", globals->getPropInt("tracelevel", 0));
         setWorkUnitFactory(createWorkUnitFactory(props));
     }
 #endif
@@ -204,9 +210,21 @@ int main(int argc, const char *argv[])
         }
         Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
         const char *action = globals->queryProp("#action");
-        if (action && (stricmp(action, "testpaged")==0)) {
+        if (action && (stricmp(action, "testpaged")==0))
+        {
             testPagedWuList(factory);
         }
+#ifdef _USE_CPPUNIT
+        else if (action && (stricmp(action, "-selftest")==0))
+        {
+            queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_time | MSGFIELD_milliTime | MSGFIELD_prefix);
+            CppUnit::TextUi::TestRunner runner;
+            CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry("WuTest");
+            runner.addTest( registry.makeTest() );
+            bool wasSucessful = runner.run( "", false );
+            return wasSucessful;
+        }
+#endif
         else if (action && (stricmp(action, "orphans")==0 || stricmp(action, "cleanup")==0))
         {
             factory->setTracingLevel(0);
@@ -327,7 +345,7 @@ int main(int argc, const char *argv[])
         }
         else if (globals->hasProp("WUID"))
         {
-            if (globals->queryProp("#action") && stricmp(globals->queryProp("#action"), "restore")==0)
+            if (action && stricmp(action, "restore")==0)
             {
                 StringBuffer from;
                 globals->getProp("FROM", from);
@@ -376,3 +394,59 @@ int main(int argc, const char *argv[])
     return 0;
 }
 
+#ifdef _USE_CPPUNIT
+#include "unittests.hpp"
+
+class WuTest : public CppUnit::TestFixture
+{
+    CPPUNIT_TEST_SUITE(WuTest);
+        CPPUNIT_TEST(testCreate);
+        CPPUNIT_TEST(testDelete);
+        CPPUNIT_TEST(testList);
+    CPPUNIT_TEST_SUITE_END();
+protected:
+    static StringArray wuids;
+    void testCreate()
+    {
+        Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
+        unsigned before = factory->numWorkUnits();
+        unsigned start = msTick();
+        for (int i = 0; i < 1000; i++)
+        {
+            VStringBuffer userId("user%d", i % 10);
+            Owned<IWorkUnit>wu = factory->createWorkUnit("WuTest", NULL, NULL, NULL);
+            wu->setState(WUStateFailed);
+            wu->setUser(userId);
+            wuids.append(wu->queryWuid());
+        }
+        unsigned after = factory->numWorkUnits();
+        DBGLOG("1000 workunits created in %d ms (%d total)", msTick()-start, after);
+        ASSERT(after-before==1000);
+        ASSERT(wuids.length() == 1000);
+    }
+
+    void testDelete()
+    {
+        ASSERT(wuids.length() == 1000);
+        Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
+        unsigned before = factory->numWorkUnits();
+        unsigned start = msTick();
+        for (int i = 0; i < 1000; i++)
+        {
+            factory->deleteWorkUnit(wuids.item(i));
+        }
+        unsigned after = factory->numWorkUnits();
+        DBGLOG("1000 workunits deleted in %d ms (%d remain)", msTick()-start, after);
+        ASSERT(before-after==1000);
+    }
+
+    void testList()
+    {
+    }
+};
+StringArray WuTest::wuids;
+
+CPPUNIT_TEST_SUITE_REGISTRATION( WuTest );
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( WuTest, "WuTest" );
+
+#endif

+ 91 - 27
plugins/cassandra/cassandraembed.cpp

@@ -2162,6 +2162,7 @@ interface ICassandraSession
 {
     virtual CassSession *querySession() const = 0;
     virtual CassandraPrepared *prepareStatement(const char *query) const = 0;
+    virtual unsigned queryTraceLevel() const = 0;
 };
 
 
@@ -2716,8 +2717,8 @@ const CassandraXmlMapping workunitsMappings [] =
 
 const CassandraXmlMapping ownerMappings [] =
 {
-    {"submitID", "text", "@submitID", stringColumnMapper},
     {"wuid", "text", NULL, rootNameColumnMapper},
+    {"submitID", "text", "@submitID", stringColumnMapper},
     {"clustername", "text", "@clusterName", stringColumnMapper},
     {"jobname", "text", "@jobName", stringColumnMapper},
     {"priorityclass", "int", "@priorityClass", intColumnMapper},
@@ -2830,7 +2831,8 @@ const CassResult *fetchDataForKey(const char *key, CassSession *session, const C
     if (key)
         selectQuery.appendf(" where %s='%s'", mappings->columnName, key); // MORE - should consider using prepared for this - is it faster?
     selectQuery.append(';');
-    DBGLOG("%s", selectQuery.str());
+    //if (traceLevel >= 2)
+    //    DBGLOG("%s", selectQuery.str());
     CassandraStatement statement(cass_statement_new(cass_string_init(selectQuery.str()), 0));
     CassandraFuture future(cass_session_execute(session, statement));
     future.wait("execute");
@@ -2883,24 +2885,33 @@ extern void simpleXMLtoCassandra(const ICassandraSession *session, CassBatch *ba
     VStringBuffer insertQuery("INSERT into HPCC.%s (%s) values (%s);", tableName.str(), names.str()+1, bindings.str()+1);
     Owned<CassandraPrepared> prepared = session->prepareStatement(insertQuery);
     CassandraStatement update(cass_prepared_bind(*prepared));
-    check(cass_statement_bind_string(update, 0, cass_string_init(wuid)));
+    check(cass_statement_bind_string(update, 0, cass_string_init(wuid))); // wuid is first column of all tables
     bindFromXML(mappings, update, inXML, 0);
     check(cass_batch_add_statement(batch, update));
 }
 
-void updateSecondaryTable(const ICassandraSession *session, CassBatch *batch, const CassandraXmlMapping *mappings, const char *wuid, IPTree *inXML,const char *prevKey)
+void deleteSecondaryByKey(const ICassandraSession *session, CassBatch *batch, const CassandraXmlMapping *mappings, const char *wuid, const char *key)
 {
-    if (prevKey)
+    if (key && *key)
     {
         StringBuffer names;
         StringBuffer tableName;
         getFieldNames(mappings, names, tableName);
-        VStringBuffer insertQuery("DELETE from HPCC.%s where %s=?;", tableName.str(), mappings[0].columnName);
+        VStringBuffer insertQuery("DELETE from HPCC.%s where wuid=? and %s=?;", tableName.str(), mappings[1].columnName);
         Owned<CassandraPrepared> prepared = session->prepareStatement(insertQuery);
         CassandraStatement update(cass_prepared_bind(*prepared));
-        check(cass_statement_bind_string(update, 0, cass_string_init(prevKey)));
+        check(cass_statement_bind_string(update, 0, cass_string_init(wuid)));
+        check(cass_statement_bind_string(update, 1, cass_string_init(key)));
+        check(cass_batch_add_statement(batch, update));
     }
-    simpleXMLtoCassandra(session, batch, mappings, wuid, inXML);
+}
+
+void updateSecondaryTable(const ICassandraSession *session, CassBatch *batch, const CassandraXmlMapping *mappings, const char *wuid, IPTree *inXML,const char *prevKey)
+{
+    if (prevKey && *prevKey)
+        deleteSecondaryByKey(session, batch, mappings, wuid, prevKey);
+    if (inXML->hasProp(mappings[1].xpath))
+        simpleXMLtoCassandra(session, batch, mappings, wuid, inXML);
 }
 
 extern void childXMLtoCassandra(const ICassandraSession *session, CassBatch *batch, const CassandraXmlMapping *mappings, const char *wuid, IPTreeIterator *elements, int defaultValue)
@@ -3215,20 +3226,34 @@ public:
 
     virtual void cleanupAndDelete(bool deldll, bool deleteOwned, const StringArray *deleteExclusions)
     {
+        const char *wuid = queryWuid();
         CLocalWorkUnit::cleanupAndDelete(deldll, deleteOwned, deleteExclusions);
-        printStackReport();
-        UNIMPLEMENTED;
+        if (!batch)
+            batch.setown(new CassandraBatch(cass_batch_new(CASS_BATCH_TYPE_UNLOGGED)));
+        Owned<CassandraPrepared> prepared = sessionCache->prepareStatement("DELETE from HPCC.workunits where wuid=?;");
+        CassandraStatement update(cass_prepared_bind(*prepared));
+        check(cass_statement_bind_string(update, 0, cass_string_init(wuid)));
+        check(cass_batch_add_statement(*batch, update));
+        deleteSecondaryByKey(sessionCache, *batch, ownerMappings, wuid, queryUser());
+        CassandraFuture futureBatch(cass_session_execute_batch(sessionCache->querySession(), *batch));
+        futureBatch.wait("execute");
+        batch.clear();
     }
 
     virtual void commit()
     {
         CLocalWorkUnit::commit();
-        StringBuffer s; toXML(p, s); DBGLOG("%s", s.str());
+        if (sessionCache->queryTraceLevel() >= 8)
+        {
+            StringBuffer s; toXML(p, s); DBGLOG("CCassandraWorkUnit::commit\n%s", s.str());
+        }
         if (batch)
         {
             const char *wuid = queryWuid();
             if (basicDirty)
+            {
                 updateSecondaryTable(sessionCache, *batch, ownerMappings, wuid, p, prevOwner);
+            }
             simpleXMLtoCassandra(sessionCache, *batch, workunitsMappings, wuid, p);  // This just does the parent row
             if (allDirty)
             {
@@ -3278,6 +3303,7 @@ public:
     {
 //        printStackReport();
 //        UNIMPLEMENTED;
+        commit();
         batch.clear();
     }
 
@@ -3379,7 +3405,7 @@ protected:
 class CCasssandraWorkUnitFactory : public CWorkUnitFactory, implements ICassandraSession
 {
 public:
-    CCasssandraWorkUnitFactory(const IPropertyTree *props) : cluster(cass_cluster_new())
+    CCasssandraWorkUnitFactory(const IPropertyTree *props) : cluster(cass_cluster_new()), randomizeSuffix(0)
     {
         StringArray options;
         Owned<IPTreeIterator> it = props->getElements("Option");
@@ -3390,8 +3416,15 @@ public:
             const char *val = item.queryProp("@value");
             if (opt && val)
             {
-                VStringBuffer optstr("%s=%s", opt, val);
-                options.append(optstr);
+                if (strieq(opt, "randomWuidSuffix"))
+                    randomizeSuffix = atoi(val);
+                else if (strieq(opt, "traceLevel"))
+                    traceLevel = atoi(val);
+                else
+                {
+                    VStringBuffer optstr("%s=%s", opt, val);
+                    options.append(optstr);
+                }
             }
         }
         cluster.setOptions(options);
@@ -3429,16 +3462,36 @@ public:
 */
     virtual CLocalWorkUnit* _createWorkUnit(const char *wuid, ISecManager *secmgr, ISecUser *secuser)
     {
-        unsigned suffix = 0;
+        unsigned suffix;
+        unsigned suffixLength;
+        if (randomizeSuffix)  // May need to enable this option if you are expecting to create hundreds of workunits / second
+        {
+            suffix = rand();
+            suffixLength = randomizeSuffix;
+        }
+        else
+        {
+            suffix = 0;
+            suffixLength = 0;
+        }
+        Owned<CassandraPrepared> prepared = prepareStatement("INSERT INTO HPCC.workunits (wuid) VALUES (?) IF NOT EXISTS;");
         loop
         {
             // Create a unique WUID by adding suffixes until we managed to add a new value
             StringBuffer useWuid(wuid);
             if (suffix)
-                useWuid.appendf("-%u", suffix);
-            VStringBuffer insert("INSERT INTO HPCC.workunits (wuid) VALUES ('%s') IF NOT EXISTS;", useWuid.str());
-            DBGLOG("%s", insert.str());
-            CassandraStatement statement(cass_statement_new(cass_string_init(insert.str()), 0));
+            {
+                useWuid.append("-");
+                for (unsigned i = 0; i < suffixLength; i++)
+                {
+                    useWuid.appendf("%c", '0'+suffix%10);
+                    suffix /= 10;
+                }
+            }
+            CassandraStatement statement(cass_prepared_bind(*prepared));
+            check(cass_statement_bind_string(statement, 0, cass_string_init(useWuid.str())));
+            if (traceLevel >= 2)
+                DBGLOG("Try creating %s", useWuid.str());
             CassandraFuture future(cass_session_execute(session, statement));
             future.wait("execute");
             CassandraResult result(cass_future_get_result(future));
@@ -3451,7 +3504,9 @@ public:
                 wu->lockRemote(true);
                 return wu.getClear();
             }
-            suffix++;
+            suffix = rand();
+            if (suffixLength<9)
+                suffixLength++;
         }
     }
     virtual CLocalWorkUnit* _openWorkUnit(const char *wuid, bool lock, ISecManager *secmgr, ISecUser *secuser)
@@ -3485,7 +3540,15 @@ public:
     virtual IConstWorkUnitIterator * getWorkUnitsSorted(WUSortField * sortorder, WUSortField * filters, const void * filterbuf,
                                                         unsigned startoffset, unsigned maxnum, const char * queryowner, __int64 * cachehint, unsigned *total,
                                                         ISecManager *secmgr, ISecUser *secuser) { UNIMPLEMENTED; }
-    virtual unsigned numWorkUnits() { UNIMPLEMENTED; }
+    virtual unsigned numWorkUnits()
+    {
+        Owned<CassandraPrepared> prepared = prepareStatement("SELECT COUNT(*) FROM HPCC.workunits;");
+        CassandraStatement statement(cass_prepared_bind(*prepared));
+        CassandraFuture future(cass_session_execute(session, statement));
+        future.wait("select count(*)");
+        CassandraResult result(cass_future_get_result(future));
+        return getUnsignedResult(NULL, getSingleResult(result));
+    }
     /*
     virtual unsigned numWorkUnitsFiltered(WUSortField * filters, const void * filterbuf, ISecManager *secmgr, ISecUser *secuser) { UNIMPLEMENTED; }
     virtual void descheduleAllWorkUnits(ISecManager *secmgr, ISecUser *secuser) { UNIMPLEMENTED; }
@@ -3494,17 +3557,20 @@ public:
     virtual void clearAborting(const char *wuid) { UNIMPLEMENTED; }
     */
     virtual CassSession *querySession() const { return session; };
+    virtual unsigned queryTraceLevel() const { return traceLevel; };
     virtual CassandraPrepared *prepareStatement(const char *query) const
     {
         CriticalBlock b(cacheCrit);
         Linked<CassandraPrepared> cached = preparedCache.getValue(query);
         if (cached)
         {
-            DBGLOG("prepareStatement: Reusing %s", query);
+            if (traceLevel >= 2)
+                DBGLOG("prepareStatement: Reusing %s", query);
             return cached.getClear();
         }
         {
-            DBGLOG("prepareStatement: Binding %s", query);
+            if (traceLevel >= 2)
+                DBGLOG("prepareStatement: Binding %s", query);
             // We don't want to block cache lookups while we prepare a new bound statement
             // Note - if multiple threads try to prepare the same (new) statement at the same time, it's not catastrophic
             CriticalUnblock b(cacheCrit);
@@ -3589,14 +3655,12 @@ private:
             const char *childName = child->queryName();
             parent->addPropTree(childName, child.getClear());
         }
-        StringBuffer buf;
-        toXML(parent, buf);
-        DBGLOG("%s", buf.str());
         Owned<IPropertyTreeIterator> iter = parent->getElements("*");
         return createConstWUIterator(iter, secmgr, secuser);
     }
 
-
+    unsigned randomizeSuffix;
+    unsigned traceLevel;
     CassandraCluster cluster;
     CassandraSession session;
     mutable CriticalSection cacheCrit;