dllserver.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  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 "jliball.hpp"
  14. #include "dllserver.hpp"
  15. #include "jiter.ipp"
  16. #include "jexcept.hpp"
  17. #include "dllservererr.hpp"
  18. #include "daclient.hpp"
  19. #include "dasds.hpp"
  20. #include "rmtclient.hpp"
  21. #include "thorplugin.hpp"
  22. #ifndef _CONTAINERIZED
  23. #include "dalienv.hpp"
  24. #endif
  25. #ifdef _WIN32
  26. #define DEFAULT_SERVER_ROOTDIR "c:\\HPCCSystems\\hpcc-data\\temp\\dllserver"
  27. #else
  28. #define DEFAULT_SERVER_ROOTDIR "/var/lib/HPCCSystems/dllserver/temp"
  29. #endif
  30. #define CONNECTION_TIMEOUT 30000
  31. static void getMangledTag(StringBuffer & path, const char * name)
  32. {
  33. path.append("Dll");
  34. unsigned len = strlen(name);
  35. path.ensureCapacity(len);
  36. for (unsigned i=0; i < len; i++)
  37. {
  38. char next = name[i];
  39. if (isalnum((byte)next))
  40. path.append(next);
  41. else
  42. path.append("_");
  43. }
  44. }
  45. static void getOldXPath(StringBuffer & path, const char * name)
  46. {
  47. path.append("/GeneratedDlls/GeneratedDll[@uid=\"").append(name).append("\"]");
  48. }
  49. static void getNewXPath(StringBuffer & path, const char * name)
  50. {
  51. path.append("/GeneratedDlls/");
  52. getMangledTag(path, name);
  53. //The following qualifier is here in case two different characters were mapped to _ - creating an ambiguous tag.
  54. path.append("[@name=\"").append(name).append("\"]");
  55. }
  56. IRemoteConnection * getEntryConnection(const char * name, unsigned mode)
  57. {
  58. StringBuffer xpath;
  59. getNewXPath(xpath, name);
  60. Owned<IRemoteConnection> connection = querySDS().connect(xpath.str(), myProcessSession(), mode, CONNECTION_TIMEOUT);
  61. if (connection)
  62. return connection.getClear();
  63. //Retain backwards compatibility for the moment
  64. getOldXPath(xpath.clear(), name);
  65. return querySDS().connect(xpath.str(), myProcessSession(), mode, CONNECTION_TIMEOUT);
  66. }
  67. //---------------------------------------------------------------------------
  68. class TreeIteratorWrapper : implements IIterator, public CInterface
  69. {
  70. public:
  71. TreeIteratorWrapper(IPropertyTreeIterator * _iter) { iter.setown(_iter); }
  72. IMPLEMENT_IINTERFACE
  73. virtual bool first()
  74. {
  75. cur.clear();
  76. return iter->first();
  77. }
  78. virtual bool next()
  79. {
  80. cur.clear();
  81. return iter->next();
  82. }
  83. virtual bool isValid()
  84. {
  85. return (cur != NULL);
  86. }
  87. virtual IInterface & get()
  88. {
  89. return *cur.getLink();
  90. }
  91. virtual IInterface & query()
  92. {
  93. return *cur;
  94. }
  95. protected:
  96. Owned<IInterface> cur;
  97. Owned<IPropertyTreeIterator> iter;
  98. };
  99. //---------------------------------------------------------------------------
  100. static void deleteLocationFiles(IDllLocation & cur, bool removeDirectory)
  101. {
  102. RemoteFilename filename;
  103. cur.getDllFilename(filename);
  104. Owned<IFile> file = createIFile(filename);
  105. file->remove();
  106. if (removeDirectory)
  107. {
  108. //Finally try and remove the directory - this will fail if it isn't empty
  109. StringBuffer path, dir;
  110. cur.getDllFilename(filename);
  111. filename.getRemotePath(path);
  112. splitDirTail(path.str(), dir);
  113. filename.setRemotePath(dir.str());
  114. file.setown(createIFile(filename));
  115. file->remove();
  116. }
  117. }
  118. class DllLocation : implements IDllLocation, public CInterface
  119. {
  120. StringAttr cacheRoot;
  121. public:
  122. DllLocation(IPropertyTree * _entryRoot, IPropertyTree * _locationRoot, const char *_cacheRoot)
  123. : cacheRoot(_cacheRoot)
  124. {
  125. entryRoot.set(_entryRoot);
  126. locationRoot.set(_locationRoot);
  127. }
  128. IMPLEMENT_IINTERFACE
  129. virtual void getDllFilename(RemoteFilename & filename)
  130. {
  131. SocketEndpoint ep(locationRoot->queryProp("@ip"));
  132. filename.setPath(ep, locationRoot->queryProp("@dll"));
  133. }
  134. virtual void getIP(IpAddress & ip)
  135. {
  136. ip.ipset(locationRoot->queryProp("@ip"));
  137. }
  138. virtual DllLocationType queryLocation()
  139. {
  140. SocketEndpoint ep(locationRoot->queryProp("@ip"));
  141. if (ep.isLocal())
  142. {
  143. RemoteFilename filename;
  144. getDllFilename(filename);
  145. StringBuffer lp;
  146. filename.getLocalPath(lp);
  147. if (strncmp(lp, cacheRoot, strlen(cacheRoot))==0)
  148. return DllLocationDirectory;
  149. return DllLocationLocal;
  150. }
  151. return DllLocationAnywhere;
  152. }
  153. virtual void remove(bool removeFiles, bool removeDirectory);
  154. protected:
  155. Owned<IPropertyTree> locationRoot;
  156. Owned<IPropertyTree> entryRoot;
  157. };
  158. static bool propsMatch(IPropertyTree & left, IPropertyTree & right, const char * prop)
  159. {
  160. const char * l = left.queryProp(prop);
  161. const char * r = right.queryProp(prop);
  162. if (!l || !r) return (l == r);
  163. return strcmp(l, r) == 0;
  164. }
  165. void DllLocation::remove(bool removeFiles, bool removeDirectory)
  166. {
  167. if (removeFiles)
  168. {
  169. try
  170. {
  171. deleteLocationFiles(*this, removeDirectory);
  172. }
  173. catch (IException * e)
  174. {
  175. EXCLOG(e, "Removing dll");
  176. e->Release();
  177. }
  178. }
  179. Owned<IRemoteConnection> conn = getEntryConnection(entryRoot->queryProp("@name"), RTM_LOCK_WRITE);
  180. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements("location");
  181. ForEach(*iter)
  182. {
  183. IPropertyTree & cur = iter->query();
  184. if (propsMatch(cur, *locationRoot, "@ip") && propsMatch(cur, *locationRoot, "@dll"))
  185. {
  186. conn->queryRoot()->removeTree(&cur);
  187. break;
  188. }
  189. }
  190. }
  191. class LocationIterator : public TreeIteratorWrapper
  192. {
  193. StringAttr cacheRoot;
  194. public:
  195. LocationIterator(IPropertyTree * _dllEntry, IPropertyTreeIterator * _iter, const char *_cacheRoot)
  196. : TreeIteratorWrapper(_iter), cacheRoot(_cacheRoot)
  197. {
  198. dllEntry.set(_dllEntry);
  199. }
  200. virtual bool first()
  201. {
  202. bool ok = TreeIteratorWrapper::first();
  203. if (ok)
  204. cur.setown(new DllLocation(dllEntry, &iter->query(), cacheRoot));
  205. return ok;
  206. }
  207. virtual bool next()
  208. {
  209. bool ok = TreeIteratorWrapper::next();
  210. if (ok)
  211. cur.setown(new DllLocation(dllEntry, &iter->query(), cacheRoot));
  212. return ok;
  213. }
  214. protected:
  215. Owned<IPropertyTree> dllEntry;
  216. };
  217. //---------------------------------------------------------------------------
  218. class DllEntry : implements IDllEntry, public CInterface
  219. {
  220. public:
  221. DllEntry(IPropertyTree *root, const char *cacheRoot, IPropertyTree *owner);
  222. IMPLEMENT_IINTERFACE
  223. virtual IIterator * createLocationIterator();
  224. virtual IDllLocation * getBestLocation();
  225. virtual IDllLocation * getBestLocationCandidate();
  226. virtual void getCreated(IJlibDateTime & dateTime)
  227. {
  228. dateTime.setString(root->queryProp("@created"));
  229. }
  230. virtual const char * queryKind()
  231. {
  232. return root->queryProp("@kind");
  233. }
  234. virtual const char * queryName()
  235. {
  236. return root->queryProp("@name");
  237. }
  238. virtual void remove(bool removeFiles, bool removeDirectory);
  239. protected:
  240. Owned<IPropertyTree> root, owner;
  241. StringAttr cacheRoot;
  242. };
  243. DllEntry::DllEntry(IPropertyTree *_root, const char *_cacheRoot, IPropertyTree *_owner)
  244. : cacheRoot(_cacheRoot)
  245. {
  246. root.set(_root);
  247. owner.set(_owner);
  248. }
  249. IIterator * DllEntry::createLocationIterator()
  250. {
  251. return new LocationIterator(root, root->getElements("location"), cacheRoot);
  252. }
  253. typedef IArrayOf<IDllLocation> LocationArray;
  254. int orderLocations(IInterface * const * pLeft, IInterface * const * pRight)
  255. {
  256. IDllLocation * left = (IDllLocation *)*pLeft;
  257. IDllLocation * right = (IDllLocation *)*pRight;
  258. return right->queryLocation() - left->queryLocation();
  259. }
  260. IDllLocation * DllEntry::getBestLocation()
  261. {
  262. LocationArray locations;
  263. Owned<IIterator> iter = createLocationIterator();
  264. ForEach(*iter)
  265. locations.append((IDllLocation &)iter->get());
  266. locations.sort(orderLocations);
  267. ForEachItemIn(idx, locations)
  268. {
  269. IDllLocation & cur = locations.item(idx);
  270. try
  271. {
  272. RemoteFilename filename;
  273. cur.getDllFilename(filename);
  274. Owned<IFile> file = createIFile(filename);
  275. Owned<IFileIO> io = file->open(IFOread);
  276. if (io)
  277. return LINK(&cur);
  278. }
  279. catch (IException * e)
  280. {
  281. StringBuffer s;
  282. EXCLOG(e, s.appendf("GetBestLocation - could not load entry for %s", root->queryProp("@name")).str());
  283. e->Release();
  284. //MORE: Should possibly remove the entry... but we don't know why we couldn't read it - could be a domain issue.
  285. }
  286. }
  287. throwError1(DSVERR_CouldNotFindDll, root->queryProp("@name"));
  288. }
  289. IDllLocation * DllEntry::getBestLocationCandidate()
  290. {
  291. Owned<IIterator> iter = createLocationIterator();
  292. Owned<IDllLocation> best;
  293. DllLocationType bestLocation = DllLocationNowhere;
  294. ForEach(*iter)
  295. {
  296. IDllLocation & cur = (IDllLocation &)iter->query();
  297. DllLocationType location = cur.queryLocation();
  298. if (location == DllLocationDirectory)
  299. return LINK(&cur);
  300. if (location > bestLocation)
  301. {
  302. best.set(&cur);
  303. bestLocation = location;
  304. }
  305. }
  306. if (!best)
  307. throwError1(DSVERR_CouldNotFindDll, root->queryProp("@name"));
  308. return best.getClear();
  309. }
  310. void DllEntry::remove(bool removeFiles, bool removeDirectory)
  311. {
  312. if (removeFiles)
  313. {
  314. Owned<IIterator> iter = createLocationIterator();
  315. // a bit nasty, but don't remove the directory for the first location, since this is where things are created in the first place.
  316. bool isFirst = true;
  317. ForEach(*iter)
  318. {
  319. try
  320. {
  321. IDllLocation & cur = (IDllLocation &)iter->query();
  322. deleteLocationFiles(cur, removeDirectory && !isFirst);
  323. }
  324. catch (IException * e)
  325. {
  326. EXCLOG(e, "Removing dll");
  327. e->Release();
  328. }
  329. isFirst = false;
  330. }
  331. }
  332. if (owner)
  333. owner->removeTree(root);
  334. else
  335. {
  336. Owned<IRemoteConnection> conn = getEntryConnection(root->queryProp("@name"), RTM_LOCK_WRITE);
  337. conn->close(true);
  338. }
  339. }
  340. class DllIterator : public TreeIteratorWrapper
  341. {
  342. public:
  343. DllIterator(IPropertyTree * _root, IPropertyTreeIterator * _iter, const char *_cacheRoot)
  344. : TreeIteratorWrapper(_iter), cacheRoot(_cacheRoot)
  345. {
  346. root.set(_root);
  347. }
  348. virtual bool first()
  349. {
  350. bool ok = TreeIteratorWrapper::first();
  351. if (ok)
  352. cur.setown(new DllEntry(&iter->query(), cacheRoot, NULL));
  353. return ok;
  354. }
  355. virtual bool next()
  356. {
  357. bool ok = TreeIteratorWrapper::next();
  358. if (ok)
  359. cur.setown(new DllEntry(&iter->query(), cacheRoot, NULL));
  360. return ok;
  361. }
  362. protected:
  363. Owned<IPropertyTree> root;
  364. StringAttr cacheRoot;
  365. };
  366. //---------------------------------------------------------------------------
  367. class DllServerBase : public CInterfaceOf<IDllServer>
  368. {
  369. public:
  370. DllServerBase(const char * _rootDir) : rootDir(_rootDir) {}
  371. virtual IIterator * createDllIterator() override;
  372. virtual void getDll(const char * name, MemoryBuffer & dllText) override;
  373. virtual IDllEntry * getEntry(const char * name) override;
  374. virtual DllLocationType isAvailable(const char * name) override;
  375. virtual ILoadedDllEntry * loadDll(const char * name, DllLocationType location);
  376. virtual ILoadedDllEntry * loadDllResources(const char * name, DllLocationType location);
  377. virtual void removeDll(const char * name, bool removeDlls, bool removeDirectory);
  378. virtual IDllEntry * createEntry(IPropertyTree *owner, IPropertyTree *entry) override;
  379. protected:
  380. DllEntry * doGetEntry(const char * name);
  381. IDllLocation * getBestMatch(const char * name);
  382. ILoadedDllEntry * doLoadDll(const char * name, DllLocationType location, bool resourcesOnly);
  383. StringAttr rootDir;
  384. };
  385. class DllServer : public DllServerBase
  386. {
  387. public:
  388. DllServer(const char * _rootDir) : DllServerBase(_rootDir) {};
  389. virtual void ensureAvailable(const char * name, DllLocationType location) override;
  390. virtual void registerDll(const char * name, const char * kind, const char * dllPath) override;
  391. protected:
  392. void copyFileLocally(RemoteFilename & targetName, RemoteFilename & sourceName);
  393. void doRegisterDll(const char * name, const char * kind, const char * dllPath);
  394. };
  395. void DllServer::copyFileLocally(RemoteFilename & targetName, RemoteFilename & sourceName)
  396. {
  397. StringBuffer sourceLocalPath,targetLocalPath;
  398. sourceName.getLocalPath(sourceLocalPath);
  399. targetLocalPath.append(rootDir);
  400. recursiveCreateDirectory(targetLocalPath.str());
  401. addPathSepChar(targetLocalPath);
  402. splitFilename(sourceLocalPath.str(),NULL,NULL,&targetLocalPath,&targetLocalPath);
  403. SocketEndpoint hostEndpoint;
  404. hostEndpoint.setLocalHost((unsigned short)0);
  405. targetName.setPath(hostEndpoint, targetLocalPath.str());
  406. OwnedIFile source = createIFile(sourceName);
  407. OwnedIFile target = createIFile(targetName);
  408. source->copyTo(target, 0, NULL, true);
  409. }
  410. IIterator * DllServerBase::createDllIterator()
  411. {
  412. Owned<IRemoteConnection> conn = querySDS().connect("/GeneratedDlls", myProcessSession(), 0, CONNECTION_TIMEOUT);
  413. IPropertyTree * root = conn->queryRoot();
  414. return conn ? (IIterator *)new DllIterator(root, root->getElements("*"), rootDir) : (IIterator *)new CNullIterator;
  415. }
  416. DllEntry * DllServerBase::doGetEntry(const char * name)
  417. {
  418. Owned<IRemoteConnection> conn = getEntryConnection(name, 0);
  419. if (conn)
  420. return new DllEntry(conn->queryRoot(), rootDir, NULL);
  421. return NULL;
  422. }
  423. IDllEntry * DllServerBase::createEntry(IPropertyTree *owner, IPropertyTree *entry)
  424. {
  425. return new DllEntry(entry, rootDir, owner);
  426. }
  427. void DllServer::doRegisterDll(const char * name, const char * kind, const char * dllPath)
  428. {
  429. RemoteFilename dllRemote;
  430. StringBuffer ipText, dllText;
  431. dllRemote.setRemotePath(dllPath);
  432. dllRemote.queryIP().getIpText(ipText);
  433. dllRemote.getLocalPath(dllText);
  434. Owned<IRemoteConnection> conn = getEntryConnection(name, RTM_LOCK_WRITE);
  435. if (conn)
  436. {
  437. /* check the entry doesn't exist already....
  438. * Ideally the connection above would be a RTM_LOCK_READ and be changed to a RTM_LOCK_WRITE only when 'location' not found
  439. */
  440. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements("location");
  441. ForEach(*iter)
  442. {
  443. IPropertyTree & cur = iter->query();
  444. if ((stricmp(cur.queryProp("@ip"),ipText.str()) == 0) &&
  445. (stricmp(cur.queryProp("@dll"),dllText.str()) == 0))
  446. return;
  447. }
  448. }
  449. else
  450. {
  451. /* in theory, two clients/threads could get here at the same time
  452. * in practice only one client/thread will be adding a unique named generated dll
  453. */
  454. StringBuffer xpath;
  455. xpath.append("/GeneratedDlls/");
  456. getMangledTag(xpath, name);
  457. conn.setown(querySDS().connect(xpath, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, CONNECTION_TIMEOUT));
  458. assertex(conn); // RTM_CREATE_QUERY will create GeneratedDlls parent node if it doesn't exist.
  459. IPropertyTree * entry = conn->queryRoot();
  460. entry->setProp("@name", name);
  461. entry->setProp("@kind", kind);
  462. Owned<IJlibDateTime> now = createDateTimeNow();
  463. StringBuffer nowText;
  464. StringBufferAdaptor strval(nowText);
  465. now->getString(strval);
  466. entry->setProp("@created", nowText.str());
  467. }
  468. IPropertyTree * locationTree = createPTree("location");
  469. locationTree->setProp("@ip", ipText.str());
  470. locationTree->setProp("@dll", dllText.str());
  471. conn->queryRoot()->addPropTree("location", locationTree);
  472. }
  473. void DllServer::ensureAvailable(const char * name, DllLocationType location)
  474. {
  475. Owned<DllEntry> match = doGetEntry(name);
  476. if (!match)
  477. throwError1(DSVERR_CouldNotFindDll, name);
  478. Owned<IDllLocation> bestLocation = match->getBestLocation();
  479. if (bestLocation->queryLocation() < location)
  480. {
  481. StringBuffer remoteDllPath, remoteLibPath;
  482. RemoteFilename sourceName, dllName, libName;
  483. bestLocation->getDllFilename(sourceName);
  484. copyFileLocally(dllName, sourceName);
  485. dllName.getRemotePath(remoteDllPath);
  486. doRegisterDll(name, "**Error**", remoteDllPath.str());
  487. assertex(isAvailable(name) >= DllLocationLocal);
  488. }
  489. }
  490. IDllLocation * DllServerBase::getBestMatch(const char * name)
  491. {
  492. Owned<DllEntry> match = doGetEntry(name);
  493. if (!match)
  494. return NULL;
  495. return match->getBestLocation();
  496. }
  497. IDllEntry * DllServerBase::getEntry(const char * name)
  498. {
  499. return doGetEntry(name);
  500. }
  501. void DllServerBase::getDll(const char * name, MemoryBuffer & dllText)
  502. {
  503. RemoteFilename filename;
  504. Owned<IDllLocation> match = getBestMatch(name);
  505. match->getDllFilename(filename);
  506. Owned<IFile> file = createIFile(filename);
  507. OwnedIFileIO io = file->open(IFOread);
  508. read(io, 0, (size32_t)-1, dllText);
  509. }
  510. DllLocationType DllServerBase::isAvailable(const char * name)
  511. {
  512. try
  513. {
  514. Owned<IDllLocation> match = getBestMatch(name);
  515. if (match)
  516. return match->queryLocation();
  517. }
  518. catch (IException *E)
  519. {
  520. E->Release();
  521. }
  522. return DllLocationNowhere;
  523. }
  524. ILoadedDllEntry * DllServerBase::loadDll(const char * name, DllLocationType type)
  525. {
  526. return doLoadDll(name, type, false);
  527. }
  528. ILoadedDllEntry * DllServerBase::loadDllResources(const char * name, DllLocationType type)
  529. {
  530. return doLoadDll(name, type, true);
  531. }
  532. ILoadedDllEntry * DllServerBase::doLoadDll(const char * name, DllLocationType type, bool resourcesOnly)
  533. {
  534. if (type < DllLocationLocal)
  535. type = DllLocationLocal;
  536. ensureAvailable(name, type);
  537. Owned<IDllLocation> location = getBestMatch(name);
  538. RemoteFilename rfile;
  539. location->getDllFilename(rfile);
  540. StringBuffer x;
  541. rfile.getPath(x);
  542. LOG(MCdebugInfo, unknownJob, "Loading dll (%s) from location %s", name, x.str());
  543. return createDllEntry(x.str(), false, NULL, resourcesOnly);
  544. }
  545. void DllServerBase::removeDll(const char * name, bool removeDlls, bool removeDirectory)
  546. {
  547. Owned<IDllEntry> entry = getEntry(name);
  548. if (entry)
  549. entry->remove(removeDlls, removeDirectory);
  550. }
  551. void DllServer::registerDll(const char * name, const char * kind, const char * dllLocation)
  552. {
  553. doRegisterDll(name, kind, dllLocation);
  554. }
  555. //---------------------------------------------------------------------------
  556. class SharedVolumeDllServer : public DllServerBase
  557. {
  558. public:
  559. SharedVolumeDllServer(const char * _mountPath) : DllServerBase(_mountPath) {};
  560. virtual void ensureAvailable(const char * name, DllLocationType location) override;
  561. virtual void registerDll(const char * name, const char * kind, const char * dllPath) override;
  562. };
  563. void SharedVolumeDllServer::ensureAvailable(const char * name, DllLocationType location)
  564. {
  565. Owned<DllEntry> match = doGetEntry(name);
  566. if (!match)
  567. throwError1(DSVERR_CouldNotFindDll, name);
  568. // MORE - if we still want to have roxie copy to directory, may need code here
  569. #ifdef _DEBUG
  570. Owned<IDllLocation> bestLocation = match->getBestLocation();
  571. assertex (bestLocation->queryLocation() >= location);
  572. #endif
  573. }
  574. void SharedVolumeDllServer::registerDll(const char * name, const char * kind, const char * dllPath)
  575. {
  576. RemoteFilename dllRemote;
  577. dllRemote.setRemotePath(dllPath);
  578. assertex(dllRemote.isLocal());
  579. StringBuffer sourceLocalPath;
  580. dllRemote.getLocalPath(sourceLocalPath);
  581. StringBuffer mountPath(rootDir);
  582. addPathSepChar(mountPath);
  583. splitFilename(sourceLocalPath.str(),NULL,NULL,&mountPath,&mountPath);
  584. // Copy file to mountpath, if not already there
  585. OwnedIFile source = createIFile(dllRemote);
  586. OwnedIFile target = createIFile(mountPath);
  587. if (!target->exists())
  588. {
  589. source->copyTo(target, 0, NULL, true);
  590. }
  591. Owned<IRemoteConnection> conn = getEntryConnection(name, RTM_LOCK_WRITE);
  592. if (conn)
  593. {
  594. /* check the entry doesn't exist already....
  595. * Ideally the connection above would be a RTM_LOCK_READ and be changed to a RTM_LOCK_WRITE only when 'location' not found
  596. */
  597. Owned<IPropertyTreeIterator> iter = conn->queryRoot()->getElements("location");
  598. ForEach(*iter)
  599. {
  600. IPropertyTree & cur = iter->query();
  601. if ((stricmp(cur.queryProp("@ip"),"localhost") == 0) &&
  602. (stricmp(cur.queryProp("@dll"),mountPath.str()) == 0))
  603. return;
  604. }
  605. }
  606. else
  607. {
  608. /* in theory, two clients/threads could get here at the same time
  609. * in practice only one client/thread will be adding a unique named generated dll
  610. */
  611. StringBuffer xpath;
  612. xpath.append("/GeneratedDlls/");
  613. getMangledTag(xpath, name);
  614. conn.setown(querySDS().connect(xpath, myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, CONNECTION_TIMEOUT));
  615. assertex(conn); // RTM_CREATE_QUERY will create GeneratedDlls parent node if it doesn't exist.
  616. IPropertyTree * entry = conn->queryRoot();
  617. entry->setProp("@name", name);
  618. entry->setProp("@kind", kind);
  619. Owned<IJlibDateTime> now = createDateTimeNow();
  620. StringBuffer nowText;
  621. StringBufferAdaptor strval(nowText);
  622. now->getString(strval);
  623. entry->setProp("@created", nowText.str());
  624. }
  625. IPropertyTree * locationTree = createPTree("location");
  626. locationTree->setProp("@ip", "localhost");
  627. locationTree->setProp("@dll", mountPath.str());
  628. conn->queryRoot()->addPropTree("location", locationTree);
  629. }
  630. //---------------------------------------------------------------------------
  631. static IDllServer * dllServer;
  632. CriticalSection dllServerCrit;
  633. IDllServer & queryDllServer()
  634. {
  635. CriticalBlock b(dllServerCrit);
  636. if (!dllServer)
  637. {
  638. #ifdef _CONTAINERIZED
  639. const char* dllserver_root = getenv("HPCC_DLLSERVER_PATH");
  640. assertex(dllserver_root != nullptr);
  641. dllServer = new SharedVolumeDllServer(dllserver_root);
  642. #else
  643. const char* dllserver_root = getenv("DLLSERVER_ROOT");
  644. StringBuffer dir;
  645. if(dllserver_root == NULL)
  646. {
  647. if (envGetConfigurationDirectory("temp","dllserver","dllserver",dir)) // not sure if different instance might be better but never separated in past
  648. dllserver_root = dir.str();
  649. else
  650. dllserver_root = DEFAULT_SERVER_ROOTDIR;
  651. }
  652. dllServer = new DllServer(dllserver_root);
  653. #endif
  654. }
  655. return *dllServer;
  656. }
  657. void closeDllServer()
  658. {
  659. CriticalBlock b(dllServerCrit);
  660. if (dllServer)
  661. {
  662. dllServer->Release();
  663. dllServer = NULL;
  664. }
  665. }
  666. void initDllServer(const char * localRoot)
  667. {
  668. CriticalBlock b(dllServerCrit);
  669. ::Release(dllServer);
  670. dllServer = new DllServer(localRoot);
  671. }
  672. void cleanUpOldDlls()
  673. {
  674. Owned<IJlibDateTime> cutoff = createDateTimeNow();
  675. unsigned year;
  676. unsigned month;
  677. unsigned day;
  678. cutoff->getGmtDate(year, month, day);
  679. //MORE: Should this test be removed?
  680. if (false && month-- == 1)
  681. {
  682. month = 12;
  683. year--;
  684. }
  685. cutoff->setGmtDate(year, month, day);
  686. //Remove all but one copy of all workunits more than a month old
  687. Owned<IIterator> dllIter = queryDllServer().createDllIterator();
  688. ForEach(*dllIter)
  689. {
  690. IDllEntry & entry = (IDllEntry &)dllIter->query();
  691. if (strcmp(entry.queryKind(), "workunit")==0)
  692. {
  693. Owned<IJlibDateTime> created = createDateTime();
  694. entry.getCreated(*created);
  695. if (created->compare(*cutoff) < 0)
  696. {
  697. Owned<IIterator> locIter = entry.createLocationIterator();
  698. bool first = true;
  699. ForEach(*locIter)
  700. {
  701. IDllLocation & location = (IDllLocation &)locIter->query();
  702. if (!first)
  703. location.remove(true, true);
  704. first = false;
  705. }
  706. }
  707. }
  708. }
  709. }