Переглянути джерело

HPCC-17973 Use a read-only common value table for attributes.

Similar to approach taken for attribute names, use a pre-populated
read-only table for names.
The table is pre-populated with values derived from environment
startup and regression suite runs.
It is also pre-populated with unsigned <10000 as many of them are
are very commonly used.

Signed-off-by: Jake Smith <jake.smith@lexisnexisrisk.com>
Jake Smith 8 роки тому
батько
коміт
9598ffe0c2

+ 2 - 2
system/jlib/jhash.hpp

@@ -459,9 +459,9 @@ protected:
     }       
 
 public:
-    CMinHashTable<C>()
+    CMinHashTable<C>(unsigned _initialSize = 7)
     {
-        htn = 7;
+        htn = _initialSize;
         n = 0;
         table = (C **)calloc(sizeof(C *),htn);
     }

+ 686 - 0
system/jlib/jptree-attrvalues.hpp

@@ -0,0 +1,686 @@
+    "_",
+    "/",
+    ".",
+    "",
+    "*",
+    "\\,",
+    "0 secs",
+    "-1"
+    "1:1",
+    "1:M",
+    "Access to cluster topology",
+    "Access to despraying of files",
+    "Access to DFU",
+    "Access to DFU exceptions",
+    "Access to DFU workunits",
+    "Access to DFU XRef",
+    "Access to ECL direct service",
+    "Access to ECL Direct service",
+    "Access to ESDL configuration service",
+    "Access to files in dropzone",
+    "Access to machine information",
+    "Access to own workunits",
+    "Access to permissions for file scopes",
+    "Access to roxie control commands",
+    "Access to SMC service",
+    "Access to SNMP metrics information",
+    "Access to spraying files",
+    "Access to thor queues",
+    "Access to upload files to dropzone",
+    "Access to workunits owned by others",
+    "Access to WS ECL service",
+    "Access to WS Logging service",
+    "Action",
+    "Action #1",
+    "Action #2",
+    "active",
+    "activities",
+    "Aggregate",
+    "Alias",
+    "any",
+    "Application",
+    "archive",
+    "ASSERT",
+    "Associated",
+    "Attr",
+    "Begin Loop",
+    "blank",
+    "blocked",
+    "Body",
+    "bytes",
+    "calculated",
+    "canstall",
+    "ca.pem",
+    "cd",
+    "certificate.cer",
+    "checkasserts",
+    "Child",
+    "Child Dataset",
+    "childfile",
+    "_childGraph",
+    "Client",
+    "Cluster",
+    "ClusterLock",
+    "ClusterTopologyAccess",
+    "cnt",
+    "coLocal",
+    "compile",
+    "compile:compile c++",
+    "compiled",
+    "compile:generate c++",
+    "compile:generate PARSE",
+    "compile:generate PARSE:analyse",
+    "compile:generate PARSE:compile",
+    "compile:generate PARSE:create structure",
+    "compile:generate PARSE:generate",
+    "compile:generate PARSE:optimize",
+    "compile:generate PARSE:prepare",
+    "compile:global implicit projects",
+    "compile:implicit projects",
+    "compile:optimize graph",
+    "compile:parseTime",
+    "compile:peephole optimize",
+    "compile:resource graph",
+    "compile:tree transform",
+    "compile:tree transform: check dependency",
+    "compile:tree transform: compound activity",
+    "compile:tree transform: convert logical",
+    "compile:tree transform: convert SetResult to Extract",
+    "compile:tree transform: expand delayed calls",
+    "compile:tree transform: global fold",
+    "compile:tree transform: hoist nested compound",
+    "compile:tree transform: merge thor",
+    "compile:tree transform: migrate",
+    "compile:tree transform: normalize",
+    "compile:tree transform: normalize.annotations",
+    "compile:tree transform: normalize.DFStransform",
+    "compile:tree transform: normalize.initial",
+    "compile:tree transform: normalize.KeyedProjectTransformer",
+    "compile:tree transform: normalize.linkedChildRows",
+    "compile:tree transform: normalize result",
+    "compile:tree transform: normalize.scope",
+    "compile:tree transform: optimize activities",
+    "compile:tree transform: optimize disk read",
+    "compile:tree transform: spot global cse",
+    "compile:tree transform: stored results",
+    "compile:tree transform: substituteClusterSize",
+    "compile:tree transform: thor hole",
+    "compile:write c++",
+    "compiling",
+    "completed",
+    "componentfiles/configxml",
+    "componentfiles/dafilesrv",
+    "componentfiles/dali",
+    "componentfiles/dfuplus",
+    "componentfiles/dfuserver",
+    "componentfiles/DropZone",
+    "componentfiles/eclagent",
+    "componentfiles/ecldirect",
+    "componentfiles/eclminus",
+    "componentfiles/eclplus",
+    "componentfiles/esdlsvcengine",
+    "componentfiles/esp",
+    "componentfiles/esploggingagent",
+    "componentfiles/espsmc",
+    "componentfiles/ftslave",
+    "componentfiles/hqltest",
+    "componentfiles/ldapServer",
+    "componentfiles/loggingmanager",
+    "componentfiles/sasha",
+    "componentfiles/SiteCertificate",
+    "componentfiles/soapplus",
+    "componentfiles/thor",
+    "componentfiles/topology",
+    "componentfiles/ws_ecl",
+    "componentfiles/wslogging",
+    "condition",
+    "conf",
+    "copy",
+    "Count",
+    "Count Project",
+    "cpp",
+    "created_by",
+    "created_for",
+    "CRON",
+    "csv",
+    "Csv Write",
+    "dafilesrv",
+    "DafilesrvProcess",
+    "DaFileSrv process",
+    "dafilesrv.xsd",
+    "dali",
+    "DaliServerProcess",
+    "dali.xsd",
+    "data",
+    "data2",
+    "data3",
+    "data4",
+    "date",
+    "Debug",
+    "Dedup",
+    "definition",
+    "Degroup",
+    "Denormalize",
+    "Denormalize Group",
+    "Dependency",
+    "_dependsOn",
+    "deploy_map.xml",
+    "deserialized",
+    "Destination",
+    "/dev*,/sys,/proc/*",
+    "dfu",
+    "DfuAccess",
+    "DFUcopy",
+    "DfuExceptions",
+    "DfuExceptionsAccess",
+    "dfuplus",
+    "DfuplusProcess",
+    "dfuplus.xsd",
+    "dfuserver",
+    "DFUserver",
+    "DFU Server",
+    "dfuserver_monitor_queue",
+    "DfuServerProcess",
+    "dfuserver_queue",
+    "dfuserver.xsd",
+    "DfuWorkunitsAccess",
+    "DfuXrefAccess",
+    "dhcpd",
+    "_diskAccessRequired",
+    "DiskUsageStats",
+    "Disk Write",
+    "dll",
+    "done",
+    "DropZone",
+    "DropZone process",
+    "dropzone.xsd",
+    "DynamicESDL",
+    "ecl",
+    "ECL",
+    "eclagent",
+    "EclAgent",
+    "ECLagent",
+    "EclAgentBuild",
+    "eclagent_config.xsd",
+    "EclAgent process",
+    "EclAgentProcess",
+    "eclcc",
+    "eclccserver",
+    "ECLCCserver",
+    "eclccserver_deploy_map.xml",
+    "EclCCServer process",
+    "EclCCServerProcess",
+    "eclccserver.xsd",
+    "ecl.common",
+    "ecldirect",
+    "EclDirectAccess",
+    "EclDirectSoapBinding",
+    "eclminus",
+    "eclplus",
+    "EclPlusProcess",
+    "eclplus.xsd",
+    "eclscheduler",
+    "eclscheduler_deploy_map.xml",
+    "EclScheduler process",
+    "EclSchedulerProcess",
+    "eclscheduler.xsd",
+    "EclWatch",
+    "Edition",
+    "End Loop",
+    "Environment_Initialize",
+    "EsdlBinding",
+    "ESDLConfigAccess",
+    "esdl_svc_engine",
+    "esdlsvcengine.xsd",
+    "esp",
+    "esploggingagent",
+    "ESPLoggingAgent",
+    "esploggingagent.xsd",
+    "EspProcess",
+    "ESP server",
+    "ESPserver",
+    "EspService",
+    "ESPservice",
+    "esp_service_ecldirect.xsd",
+    "esp_service_module",
+    "ESP services for SMC",
+    "esp_service_wsecl2.xsd",
+    "espsmc",
+    "espsmcservice.xsd",
+    "esp.xsd",
+    "Exception",
+    "Exceptions",
+    "expandpersistinputdependencies",
+    "fAddFileRelationship",
+    "fAddSuperFile",
+    "failed",
+    "failonleaks",
+    "failure",
+    "false",
+    "False",
+    "falseval",
+    "farm1",
+    "farm2",
+    "fCreateSuperFile",
+    "fDeleteLogicalFile",
+    "fDeleteSuperFile",
+    "fFileExists",
+    "fFinishSuperFileTransaction",
+    "fgetParseTree",
+    "fGetSuperFileSubCount",
+    "file",
+    "File",
+    "FileDesprayAccess",
+    "FileIOAccess",
+    "_fileName",
+    "__filepos",
+    "filepos",
+    "__fileposition__",
+    "files",
+    "Files",
+    "FileScopeAccess",
+    "fileservices",
+    "FileSprayAccess",
+    "FilesRead",
+    "FileUploadAccess",
+    "Filter",
+    "Filtered Project",
+    "finished",
+    "Firstn",
+    "flat",
+    "float",
+    "Format",
+    "fRemoveSuperFile",
+    "_fromChild",
+    "fSetColumnMapping",
+    "fStartSuperFileTransaction",
+    "fSuperFileExists",
+    "ftslave",
+    "ftslave_linux.xsd",
+    "FTSlave process",
+    "FTSlaveProcess",
+    "function",
+    "Funnel",
+    "global",
+    "_globalUsageCount",
+    "graph",
+    "Graph",
+    "graphBin",
+    "_graphid",
+    "_graphId",
+    "_graphIndependent",
+    "Graphs",
+    "Group",
+    "grouped",
+    "Grouped Aggregate",
+    "Grouped Dedup",
+    "Grouped Filter",
+    "Grouped Iterate",
+    "Grouped Normalize",
+    "Grouped Process",
+    "Grouped Project",
+    "Grouped Rollup",
+    "Grouped Sort",
+    "Grouped Split",
+    "Hash Aggregate",
+    "Hash Dedup",
+    "Hash Distribute",
+    "hpcc",
+    "HPCCSystems",
+    "hqltest",
+    "HqlTestProcess",
+    "hthor",
+    "HThorServer",
+    "http",
+    "httpd",
+    "http://www.w3.org/1999/XMLSchema-instance",
+    "id",
+    "If",
+    "ignore",
+    "import",
+    "in",
+    "_indexFileName",
+    "Index Write",
+    "inds",
+    "infile",
+    "initial",
+    "Inline Dataset",
+    "Inline Row",
+    "inputs",
+    "_internal",
+    "isokay",
+    "_isSpill",
+    "_isTransformSpill",
+    "Item",
+    "Iterate",
+    "Job",
+    "jobtemp",
+    "Join",
+    "json",
+    "KB",
+    "kerberos",
+    "key",
+    "_kind",
+    "lang",
+    "layouttranslationenabled",
+    "ldapServer",
+    "LDAPServerProcess",
+    "ldapserver.xsd",
+    "LDS",
+    "LEFT",
+    "lhs",
+    "lib_fileservices",
+    "libfileservices.so",
+    "lib_parselib",
+    "libparselib.so",
+    "lib_stringlib",
+    "libstringlib.so",
+    "lib_unicodelib",
+    "libunicodelib.so",
+    "libworkunitservices.so",
+    "Lightweight Self Join",
+    "link",
+    "linux",
+    "Linux",
+    "linuxmachine",
+    "local",
+    "Local Dedup",
+    "localdomain",
+    "Local Group",
+    "localhost",
+    "Local Index Write",
+    "Local Join",
+    "Local Result",
+    "Local Sort",
+    "Local Sorted",
+    "location",
+    "lock",
+    "log",
+    "loggingmanager",
+    "LoggingManager",
+    "loggingmanager.xsd",
+    "loggingservice_binding",
+    "logicalName",
+    "lookupjoin",
+    "Lookup Join",
+    "Loop",
+    "_loopid",
+    "MachineInfoAccess",
+    "makechildren",
+    "makedataset",
+    "master",
+    "matches",
+    "MatchSmith",
+    "maxcompilethreads",
+    "maxCompileThreads",
+    "maxseeklookahead",
+    "Merge",
+    "Merge Join",
+    "MetricsAccess",
+    "mirror",
+    "Monitor",
+    "msg",
+    "msgs",
+    "name",
+    "no",
+    "node",
+    "nofold",
+    "none",
+    "normal",
+    "Normalize",
+    "ns",
+    "null",
+    "Null",
+    "NumAllocations",
+    "NumAllocationScans",
+    "NumAtmostTriggered",
+    "NumDiskAccepted",
+    "NumDiskRowsRead",
+    "NumDiskSeeks",
+    "NumGroupMax",
+    "NumGroups",
+    "NumIndexAccepted",
+    "NumIndexMerges",
+    "NumIndexNullSkips",
+    "NumIndexRejected",
+    "NumIndexRowsRead",
+    "NumIndexScans",
+    "NumIndexSeeks",
+    "NumIndexSkips",
+    "NumIndexWildSeeks",
+    "NumLeafCacheAdds",
+    "NumLeafCacheHits",
+    "NumNodeCacheAdds",
+    "NumNodeCacheHits",
+    "numrecs",
+    "_numResults",
+    "NumRowsProcessed",
+    "NumStarted",
+    "NumStopped",
+    "Nway Graph Input",
+    "once",
+    "OnWarning",
+    "OnWarnings",
+    "options",
+    "Options",
+    "ordered",
+    "OriginalTextFilesEclPath",
+    "OriginalTextFilesIp",
+    "OriginalTextFilesOsPath",
+    "OrigName",
+    "OthersWorkunitsAccess",
+    "ou=EclDirectAccess,ou=EspServices,ou=ecl",
+    "ou=EspServices,ou=ecl",
+    "ou=SMC,ou=EspServices,ou=ecl",
+    "ou=workunits,ou=ecl",
+    "ou=WsEcl,ou=EspServices,ou=ecl",
+    "OwnWorkunitsAccess",
+    "parallel",
+    "Parameters",
+    "_parentActivity",
+    "Parse",
+    "Part",
+    "partial",
+    "Parts",
+    "Pid",
+    "Pipe Through",
+    "Plugin",
+    "PluginProcess",
+    "Plugins",
+    "plugin.xsd",
+    "predictedCount",
+    "preload",
+    "privatekey.cer",
+    "Process",
+    "progress",
+    "Progress",
+    "Project",
+    "Quantile",
+    "query",
+    "Query",
+    "Queue",
+    "queued",
+    "Read",
+    "Read Local Result",
+    "_record_layout",
+    "recordSize",
+    "Recovery",
+    "Relationship",
+    "Relationships",
+    "reqd",
+    "result",
+    "Result",
+    "Results",
+    "RIGHT",
+    "ro1",
+    "rolledup",
+    "Root access to ECL Direct service",
+    "Root access to SMC service",
+    "Root access to WS ECL service",
+    "Root access to WS Logging service",
+    "rootGraph",
+    "Row",
+    "rowCount",
+    "roxie",
+    "Roxie",
+    "Roxie cluster",
+    "RoxieCluster",
+    "RoxieControlAccess",
+    "roxie_deploy_map.xml",
+    "RoxieServer",
+    "roxie.xsd",
+    "run",
+    "running",
+    "Running",
+    "Sample",
+    "sasha",
+    "SashaServer",
+    "Sasha Server process",
+    "SashaServerProcess",
+    "sasha.xsd",
+    "Schedule",
+    "SchemaRaw",
+    "Scope",
+    "sds",
+    "SDS_Initialize",
+    "section",
+    "Select Nth",
+    "Self Join",
+    "sequential",
+    "Sequential",
+    "Server",
+    "ServerList",
+    "setup",
+    "ShortText",
+    "single",
+    "SiteCertificate",
+    "SiteCertificate.xsd",
+    "SizePeakMemory",
+    "Skip Limit",
+    "smart",
+    "SmcAccess",
+    "soapplus",
+    "SoapPlusProcess",
+    "soapplus.xsd",
+    "somefile",
+    "Sort",
+    "sortedids",
+    "sortfixed",
+    "sortvar",
+    "Source",
+    "_sourceActivity",
+    "_sourceIndex",
+    "spillReason",
+    "Split",
+    "sq",
+    "started",
+    "State",
+    "Statistic",
+    "Statistics",
+    "Stats",
+    "std",
+    "std.system",
+    "str",
+    "Str",
+    "stripprefixlist",
+    "Subfile",
+    "SubFile",
+    "subgraph",
+    "submitted",
+    "success",
+    "summary",
+    "SuperFile",
+    "SuperOwner",
+    "supplied",
+    "Switch",
+    "sz",
+    "_targetActivity",
+    "targetclustertype",
+    "_targetIndex",
+    "targetip",
+    "@temp",
+    "temp",
+    "@temp/esp_service.xsl",
+    "Temporaries",
+    "temporary",
+    "tempr",
+    "Text",
+    "textsearch",
+    "TextSearch",
+    "thor",
+    "Thor",
+    "thorlib",
+    "Thorlib",
+    "ThorMaster",
+    "Thor process",
+    "ThorQueueAccess",
+    "thorversion",
+    "thor.xsd",
+    "TimeElapsed",
+    "TimeLocalExecute",
+    "TimeRemaining",
+    "TimeSortElapsed",
+    "topLevelKey",
+    "Top N",
+    "topology",
+    "Topology",
+    "topology.xsd",
+    "Total cluster time",
+    "totalRowCount",
+    "Total thor time",
+    "Tracing",
+    "true",
+    "True",
+    "ts",
+    "TS",
+    "undefined",
+    "unknown",
+    "_updateIfChanged",
+    "updown",
+    "US",
+    "user",
+    "utf8n",
+    "Value",
+    "Variable",
+    "Variables",
+    "view",
+    "wait",
+    "_when",
+    "WhenCompiled",
+    "WhenCreated",
+    "WhenGraphFinished",
+    "WhenGraphStarted",
+    "WhenQueryFinished",
+    "WhenQueryStarted",
+    "WhenWorkunitModified",
+    "Windows",
+    "Workflow",
+    "workunit",
+    "WorkUnit",
+    "Workunit DLL",
+    "workunit:optimize graph",
+    "workunit:resource graph",
+    "workunit:tree transform: optimize disk read",
+    "ws_access",
+    "ws_dfu",
+    "ws_dfuxref",
+    "ws_ecl",
+    "WsEclAccess",
+    "WS ECL Service",
+    "ws_eclSoapBinding",
+    "ws_esdlconfig",
+    "ws_fileio",
+    "ws_fs",
+    "wslogging",
+    "WsLoggingAccess",
+    "wslogging.xsd",
+    "ws_machine",
+    "ws_smc",
+    "WsSMC",
+    "ws_topology",
+    "ws_workunits",
+    "xgmml",
+    "xml",
+    "xmlValue",
+    "xslt",
+    "Yes",

+ 60 - 2
system/jlib/jptree.cpp

@@ -66,6 +66,7 @@ IPropertyTreeIterator *createNullPTreeIterator() { return LINK(nullPTreeIterator
 
 #ifdef USE_READONLY_ATOMTABLE
 RONameTable *AttrStrUnionWithTable::roNameTable = nullptr;
+RONameTable *AttrStrUnionWithValueTable::roValueTable = nullptr;
 #endif
 static AtomRefTable *keyTable = nullptr;
 static AtomRefTable *keyTableNC = nullptr;
@@ -82,6 +83,11 @@ static const char * roAttributes[] =
 #include "jptree-attrs.hpp"    // potentially auto-generated
     nullptr
 };
+static const char * roAttributeValues[] =
+{
+#include "jptree-attrvalues.hpp"    // potentially auto-generated
+    nullptr
+};
 
 void initializeRoTable()
 {
@@ -89,6 +95,49 @@ void initializeRoTable()
     {
         AttrStrUnionWithTable::roNameTable->find(*attr, true);
     }
+    for (const char **value = roAttributeValues; *value; value++)
+    {
+        AttrStrUnionWithValueTable::roValueTable->find(*value, true);
+    }
+    // also populate read-only value table by generating some common constants
+    StringBuffer constStr;
+    for (unsigned c=0; c<1000; c++) // common unsigned values in attributes
+    {
+        constStr.clear().append(c);
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+    }
+    for (unsigned c=1; c<=400; c++) // outer graphs
+    {
+        constStr.clear().append("graph").append(c);
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+        constStr.clear().append("Graph graph ").append(c);
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+    }
+    for (unsigned c=1; c<=200; c++) // subgraphs
+    {
+        constStr.clear().append("sg").append(c);
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+    }
+    for (unsigned c=1; c<=200; c++) // Edge 0
+    {
+        constStr.clear().append(c).append("_0");
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+    }
+    for (unsigned c=0; c<35; c++)
+    {
+        char ch = c<9 ? ('1' + c) : ('A' + (c-9));
+        constStr.clear().append("~spill::").append(ch); // spills
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+        constStr.clear().append("gl").append(ch); // graph results
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+        constStr.clear().append("mf").append(ch); // meta factories
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+    }
+    for (unsigned c=1; c<=10; c++) // global auto attributes
+    {
+        constStr.clear().append("auto").append(c);
+        AttrStrUnionWithValueTable::roValueTable->find(constStr.str(), true);
+    }
 #ifdef TRACE_ATOM_SIZE
     // If you are wanting an idea of the savings from use of the RO hash table, it may be useful to reset
     // the counts here. But it's more correct to actually leave them in place.
@@ -99,10 +148,17 @@ void initializeRoTable()
     for (const char **a = roAttributes; *a; a++)
     {
         // sanity check
-        unsigned idx = AttrStrUnionWithTable::roNameTable->findIndex(*a,AttrStrC::getHash(*a));
+        unsigned idx = AttrStrUnionWithTable::roNameTable->findIndex(*a, AttrStrC::getHash(*a));
         AttrStrC *val = AttrStrUnionWithTable::roNameTable->getIndex(idx);
         assert(val && val->eq(*a));
     }
+    for (const char **v = roAttributeValues; *v; v++)
+    {
+        // sanity check
+        unsigned idx = AttrStrUnionWithValueTable::roValueTable->findIndex(*v, AttrStrC::getHash(*v));
+        AttrStrC *val = AttrStrUnionWithValueTable::roValueTable->getIndex(idx);
+        assert(val && val->eq(*v));
+    }
 #endif
 }
 #endif
@@ -111,7 +167,8 @@ MODULE_INIT(INIT_PRIORITY_JPTREE)
 {
     nullPTreeIterator = new NullPTreeIterator;
 #ifdef USE_READONLY_ATOMTABLE
-    AttrStrUnionWithTable::roNameTable = new RONameTable;
+    AttrStrUnionWithTable::roNameTable = new RONameTable(255);
+    AttrStrUnionWithValueTable::roValueTable = new RONameTable(4095);
     initializeRoTable();
 #endif
     keyTable = new AtomRefTable;
@@ -128,6 +185,7 @@ MODULE_EXIT()
     keyTableNC->Release();
 #ifdef USE_READONLY_ATOMTABLE
     delete AttrStrUnionWithTable::roNameTable;
+    delete AttrStrUnionWithValueTable::roValueTable;
 #endif
     free(freelist);
     freelist = NULL;

+ 31 - 1
system/jlib/jptree.ipp

@@ -517,15 +517,45 @@ struct AttrStrUnionWithTable : public AttrStrUnion
     }
     static RONameTable *roNameTable;
 };
+
+struct AttrStrUnionWithValueTable : public AttrStrUnion
+{
+    inline const char *get() const
+    {
+        if (flag==3) // no point in also checking !isPtr() afaics
+            return roValueTable->getIndex(idx2)->str_DO_NOT_USE_DIRECTLY;  // Should probably rename this back now!
+        return AttrStrUnion::get();
+    }
+    bool set(const char *key)
+    {
+        if (key)
+        {
+            unsigned idx = roValueTable->findIndex(key, AttrStrC::getHash(key));
+            if (idx != (unsigned) -1)
+            {
+                assert(idx <= 0xffff);
+                flag = 3;
+                idx2 = idx;
+                return true;
+            }
+#ifdef _TRACE_VALUE_MISSES
+            PROGLOG("notfound key = %s", key);
+#endif
+        }
+        return false;
+    }
+    static RONameTable *roValueTable;
+};
 #else
 typedef AttrStrUnion AttrStrUnionWithTable;
+typedef AttrStrUnion AttrStrUnionWithValueTable;
 
 #endif
 
 struct AttrValue
 {
     AttrStrUnionWithTable key;
-    AttrStrUnion value;
+    AttrStrUnionWithValueTable value;
 };