package.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jprop.hpp"
  15. #include "jptree.hpp"
  16. #include "pkgimpl.hpp"
  17. #include "dadfs.hpp"
  18. #include "eclrtl.hpp"
  19. #include "jregexp.hpp"
  20. #include "dasds.hpp"
  21. #define SDS_LOCK_TIMEOUT (5*60*1000) // 5mins, 30s a bit short
  22. //wrap the hashing function here to simplify template dependencies
  23. hash64_t pkgHash64Data(size32_t len, const void *buf, hash64_t hval)
  24. {
  25. return rtlHash64Data(len, buf, hval);
  26. }
  27. CPackageNode::CPackageNode(IPropertyTree *p)
  28. {
  29. if (p)
  30. node.set(p);
  31. else
  32. node.setown(createPTree("HpccPackages"));
  33. StringBuffer xml;
  34. toXML(node, xml);
  35. hash = rtlHash64Data(xml.length(), xml.str(), 9994410);
  36. }
  37. // Merge base package environment into mergedEnvironment
  38. void CPackageNode::mergeEnvironment(const CPackageNode *base)
  39. {
  40. Owned<IPropertyIterator> envIterator = base->mergedEnvironment->getIterator();
  41. ForEach(*envIterator)
  42. {
  43. const char *id = envIterator->getPropKey();
  44. const char *val = base->mergedEnvironment->queryProp(id);
  45. if (id && val && !mergedEnvironment->hasProp(id))
  46. mergedEnvironment->setProp(id, val);
  47. }
  48. }
  49. // Use local package and its bases to resolve superfile name list of subfiles via all supported resolvers
  50. ISimpleSuperFileEnquiry *CPackageNode::resolveSuperFile(const char *superFileName) const
  51. {
  52. // Order of resolution:
  53. // 1. SuperFiles named in local package
  54. // 2. SuperFiles named in bases
  55. // There is no dali or local case - a superfile that is resolved in dali must also resolve the subfiles there (and is all done in the resolveLFNusingDali method)
  56. if (superFileName && *superFileName && node)
  57. {
  58. if (*superFileName=='~')
  59. superFileName++;
  60. StringBuffer xpath;
  61. Owned<IPropertyTreeIterator> subFiles = lookupElements(makeSuperFileXPath(xpath, superFileName), "SubFile");
  62. if (subFiles)
  63. {
  64. Owned<CPackageSuperFileArray> result = new CPackageSuperFileArray(*subFiles);
  65. return result.getClear();
  66. }
  67. }
  68. return NULL;
  69. }
  70. // Load mergedEnvironment from local XML node
  71. void CPackageNode::loadEnvironment()
  72. {
  73. mergedEnvironment.setown(createProperties(true));
  74. Owned<IPropertyTreeIterator> envIterator = node->getElements("Environment");
  75. ForEach(*envIterator)
  76. {
  77. IPropertyTree &env = envIterator->query();
  78. const char *id = env.queryProp("@id");
  79. const char *val = env.queryProp("@value");
  80. if (!val)
  81. val = env.queryProp("@val"); // Historically we used val here - not sure why... other parts of package file used value
  82. if (id && val)
  83. mergedEnvironment->setProp(id, val);
  84. else
  85. {
  86. StringBuffer s;
  87. toXML(&env, s);
  88. throw MakeStringException(PACKAGE_MISSING_ID, "PACKAGE_ERROR: Environment element missing id or value: %s", s.str());
  89. }
  90. }
  91. Owned<IAttributeIterator> attrs = node->getAttributes();
  92. for(attrs->first(); attrs->isValid(); attrs->next())
  93. {
  94. StringBuffer s("control:");
  95. s.append(attrs->queryName()+1); // queryName() has a leading @, hence the +1
  96. mergedEnvironment->setProp(s.str(), attrs->queryValue());
  97. }
  98. }
  99. bool CPackageNode::validate(StringArray &warn, StringArray &err) const
  100. {
  101. if (!node)
  102. return true;
  103. StringAttr packageId = node->queryProp("@id");
  104. if (packageId.isEmpty())
  105. err.append("Package has no id attribute");
  106. Owned<IPropertyTreeIterator> files = node->getElements("SuperFile");
  107. ForEach(*files)
  108. {
  109. IPropertyTree &super = files->query();
  110. StringAttr superId = super.queryProp("@id");
  111. if (superId.isEmpty())
  112. err.append("SuperFile has no id attribute");
  113. if (!super.hasProp("SubFile"))
  114. {
  115. VStringBuffer msg("Package['%s']/SuperFile['%s'] has no SubFiles defined", packageId.sget(), superId.sget());
  116. warn.append(msg.str());
  117. }
  118. }
  119. return true;
  120. }
  121. CHpccPackage *createPackage(IPropertyTree *p)
  122. {
  123. return new CHpccPackage(p);
  124. }
  125. //================================================================================================
  126. // CPackageMap - an implementation of IPackageMap using a string map
  127. //================================================================================================
  128. IHpccPackageMap *createPackageMapFromPtree(IPropertyTree *t, const char *queryset, const char *id)
  129. {
  130. Owned<CHpccPackageMap> pm = new CHpccPackageMap(id, queryset, true);
  131. pm->load(t);
  132. return pm.getClear();
  133. }
  134. IHpccPackageMap *createPackageMapFromXml(const char *xml, const char *queryset, const char *id)
  135. {
  136. Owned<IPropertyTree> t = createPTreeFromXMLString(xml);
  137. return createPackageMapFromPtree(t, queryset, id);
  138. }
  139. //================================================================================================
  140. // CHpccPackageSet - an implementation of IHpccPackageSet
  141. //================================================================================================
  142. CHpccPackageSet::CHpccPackageSet(const char *_process) : process(_process)
  143. {
  144. Owned<IPropertyTree> ps = resolvePackageSetRegistry(process, true);
  145. if (ps)
  146. load(ps);
  147. }
  148. void CHpccPackageSet::load(IPropertyTree *xml)
  149. {
  150. Owned<IPropertyTreeIterator> it = xml->getElements("PackageMap[@active='1']"); //only active for now
  151. ForEach(*it)
  152. {
  153. IPropertyTree &tree = it->query();
  154. if (!tree.hasProp("@id"))
  155. continue;
  156. Owned<CHpccPackageMap> pm = new CHpccPackageMap(tree.queryProp("@id"), tree.queryProp("@querySet"), true);
  157. pm->load(tree.queryProp("@id"));
  158. packageMaps.append(*pm.getClear());
  159. }
  160. }
  161. const IHpccPackageMap *CHpccPackageSet::queryActiveMap(const char *queryset) const
  162. {
  163. ForEachItemIn(i, packageMaps)
  164. {
  165. CHpccPackageMap &pm = packageMaps.item(i);
  166. StringAttr &match = pm.querySet;
  167. if (!match.length())
  168. continue;
  169. if (isWildString(match))
  170. {
  171. if (WildMatch(queryset, match))
  172. return &pm;
  173. }
  174. else if (streq(queryset, match))
  175. return &pm;
  176. }
  177. return NULL;
  178. }
  179. extern WORKUNIT_API IHpccPackageSet *createPackageSet(const char *process)
  180. {
  181. return new CHpccPackageSet(process);
  182. }
  183. extern WORKUNIT_API IPropertyTree * getPackageMapById(const char * id, bool readonly)
  184. {
  185. StringBuffer xpath;
  186. xpath.append("/PackageMaps/PackageMap[@id=\"").append(id).append("\"]");
  187. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  188. if (!conn)
  189. return NULL;
  190. return conn->getRoot();
  191. }
  192. extern WORKUNIT_API IPropertyTree * getPackageSetById(const char * id, bool readonly)
  193. {
  194. StringBuffer xpath;
  195. xpath.append("/PackageSets/PackageSet[@id=\"").append(id).append("\"]");
  196. Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), readonly ? RTM_LOCK_READ : RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
  197. if (!conn)
  198. return NULL;
  199. return conn->getRoot();
  200. }
  201. extern WORKUNIT_API IPropertyTree * resolvePackageSetRegistry(const char *process, bool readonly)
  202. {
  203. Owned<IRemoteConnection> globalLock = querySDS().connect("/PackageSets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, SDS_LOCK_TIMEOUT);
  204. Owned<IPropertyTree> psroot = globalLock->getRoot();
  205. StringBuffer xpath;
  206. xpath.append("PackageSet[@process=\"").append(process).append("\"]");
  207. IPropertyTree *ps = psroot->queryPropTree(xpath);
  208. if (ps)
  209. return getPackageSetById(ps->queryProp("@id"), readonly);
  210. Owned<IPropertyTreeIterator> it = psroot->getElements("PackageSet[@process]");
  211. ForEach(*it)
  212. {
  213. const char *match = it->query().queryProp("@process");
  214. const char *id = it->query().queryProp("@id");
  215. if (id && isWildString(match) && WildMatch(process, match))
  216. return getPackageSetById(id, readonly);
  217. }
  218. return NULL;
  219. }