ExtrSvcs-ExternalServicesImpl.xml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
  3. "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
  4. <sect1 id="External_Service_Implementation">
  5. <title>External Service Implementation</title>
  6. <para>ECL external system services<indexterm>
  7. <primary>external system services</primary>
  8. </indexterm><indexterm>
  9. <primary>External Service</primary>
  10. </indexterm> are implemented as exported functions in a .SO (Shared
  11. Object)<indexterm>
  12. <primary>.SO</primary>
  13. </indexterm><indexterm>
  14. <primary>Shared Object</primary>
  15. </indexterm>. An ECL system service .SO can contain one or more services
  16. and (possibly) a single .SO initialization routine. All system service
  17. libraries must be thread safe.</para>
  18. <para>All exported functions in the .SO (hereafter referred to as "entry
  19. points") must adhere to certain calling and naming conventions. First, entry
  20. points must use the "C" naming convention. That is, function name decoration
  21. (like that used by C++) is not allowed.</para>
  22. <para>Second, the storage class of __declspec(dllexport) and declaration
  23. type _cdecl need to be declared for Windows/Microsoft C++ applications.
  24. Typically, SERVICE_CALL is defined as _declspec(dllexport) and SERVICE_API
  25. is defined as _cdecl for Windows, and left as nulls for Linux. For
  26. example:</para>
  27. <programlisting>Extern "C" _declspec(dllexport) unsigned _cdecl Countchars(const unsigned len, const char *string)</programlisting>
  28. <para><emphasis role="bold">Note</emphasis>: The use of an external SERVICE
  29. may be restricted to signed modules. See Code Signing in the ECL
  30. Programmer's Guide.</para>
  31. <sect2 id="DLL_Initialization">
  32. <title>.SO Initialization</title>
  33. <para>The following is an example prototype for an ECL (.SO) system
  34. service initialization routine:</para>
  35. <programlisting>extern "C" void stdcall &lt;functionName&gt; (IEclWorkUnit *w);</programlisting>
  36. <para>The IEclWorkUnit is transparent to the application, and can be
  37. declared as Struct IEclWorkUnit; or simply referred to as a void *.</para>
  38. <para>In addition, an initialization routine should retain a reference to
  39. its "Work Unit." Typically, a global variable is used to retain this
  40. value. For example:</para>
  41. <programlisting>IEclWorkUnit *workUnit;
  42. // global variable to hold the Work Unit reference
  43. extern "C" void SERVICE_API myInitFunction (IEclWorkUnit *w)
  44. {
  45. workUnit = w; // retain reference to "Work Unit"
  46. }
  47. </programlisting>
  48. </sect2>
  49. <sect2 id="Entry_Points">
  50. <title>Entry Points</title>
  51. <para>Entry points have the same definition requirements as initialization
  52. routines. However, unlike initialization routines, entry points can return
  53. a value. Valid return types are listed below. The following is an example
  54. of an entry point:</para>
  55. <programlisting>extern "C" __int64 SERVICE_API PrnLog(unsigned long len, const char *val)
  56. {
  57. }
  58. </programlisting>
  59. </sect2>
  60. <sect2 id="SERVICE_Structure_external">
  61. <title>SERVICE Structure - external<indexterm>
  62. <primary>SERVICE Structure</primary>
  63. </indexterm></title>
  64. <para>For each system service defined, a corresponding ECL function
  65. prototype must be declared (see <emphasis role="bold">SERVICE
  66. Structure</emphasis>).</para>
  67. <programlisting> servicename := SERVICE
  68. functionname(parameter list) [: keyword = value];
  69. END;
  70. For example:
  71. email := SERVICE
  72. simpleSend(STRING address, STRING template, STRING subject)
  73. : LIBRARY='ecl2cw', INITFUNCTION='initEcl2Cw';
  74. END;
  75. </programlisting>
  76. </sect2>
  77. <sect2 id="Keywords">
  78. <title>Keywords<indexterm>
  79. <primary>Service Function Keywords</primary>
  80. </indexterm></title>
  81. <para>This is the list of valid keywords for use in service function
  82. prototypes:</para>
  83. <para><informaltable colsep="1" frame="all" rowsep="1">
  84. <tgroup cols="2">
  85. <colspec colwidth="115.95pt" />
  86. <colspec />
  87. <tbody>
  88. <row>
  89. <entry><emphasis>LIBRARY</emphasis></entry>
  90. <entry>Indicates the name of the .SO module an entry point is
  91. defined in.</entry>
  92. </row>
  93. <row>
  94. <entry><emphasis>ENTRYPOINT</emphasis></entry>
  95. <entry>Specifies a name for the entry point. By default, the
  96. name of the entry point is the function name.</entry>
  97. </row>
  98. <row>
  99. <entry><emphasis>INITFUNCTION</emphasis></entry>
  100. <entry>Specifies the name of the initialization routine defined
  101. in the module containing the entry point. Currently, the
  102. initialization function is called once.</entry>
  103. </row>
  104. <row>
  105. <entry><emphasis>INCLUDE<indexterm>
  106. <primary>INCLUDE</primary>
  107. </indexterm></emphasis></entry>
  108. <entry>Indicates the function prototype is in the specified
  109. include file, so the generated CPP must #include that file. If
  110. INCLUDE is not specified, the C++ prototype is generated from
  111. the ECL function definition.</entry>
  112. </row>
  113. <row>
  114. <entry><emphasis>C</emphasis></entry>
  115. <entry>Indicates the generated C++ prototype is enclosed within
  116. an extern "C" rather than just extern.</entry>
  117. </row>
  118. <row>
  119. <entry><emphasis>PURE<indexterm>
  120. <primary>PURE</primary>
  121. </indexterm></emphasis></entry>
  122. <entry>Indicates the function returns the same result every time
  123. you call it with the same parameters and has no side effects.
  124. This allows the optimizer to make more efficient calls to the
  125. function in some cases.</entry>
  126. </row>
  127. <row>
  128. <entry><emphasis>ONCE<indexterm>
  129. <primary>ONCE</primary>
  130. </indexterm></emphasis></entry>
  131. <entry>Indicates the function has no side effects and is
  132. evaluated at query execution time, even if the parameters are
  133. constant. This allows the optimizer to make more efficient calls
  134. to the function in some cases.</entry>
  135. </row>
  136. <row>
  137. <entry><emphasis>FOLD<indexterm>
  138. <primary>FOLD</primary>
  139. </indexterm></emphasis></entry>
  140. <entry>Specifies that the function is evaluated at compile time
  141. if all parameters are constants. Specifying FOLD to the SERVICE
  142. applys it to all function definitions in the service - in such
  143. cases NOFOLD may be useful to override this default for
  144. individual functions that are not suitable for constant
  145. folding.</entry>
  146. </row>
  147. <row>
  148. <entry><emphasis>NOFOLD<indexterm>
  149. <primary>NOFOLD</primary>
  150. </indexterm></emphasis></entry>
  151. <entry>Specifies that the service is not suitable for constant
  152. folding.</entry>
  153. </row>
  154. <row>
  155. <entry><emphasis>ACTION</emphasis></entry>
  156. <entry>Indicates the function has side effects and requires the
  157. optimizer to not remove calls to the function.</entry>
  158. </row>
  159. <row>
  160. <entry><emphasis>CONTEXT</emphasis></entry>
  161. <entry>Internal use, only. Indicates an extra internal context
  162. parameter (ICodeContext *) is passed to the function. This must
  163. be the first function parameter.</entry>
  164. </row>
  165. <row>
  166. <entry><emphasis>GLOBALCONTEXT</emphasis></entry>
  167. <entry>Internal use, only. Same as CONTEXT, but there are
  168. restrictions on where the function can be used (for example, not
  169. in a TRANSFORM).</entry>
  170. </row>
  171. <row>
  172. <entry><emphasis>CTXMETHOD</emphasis></entry>
  173. <entry>Internal use, only. Indicates the function is actually a
  174. method of the internal code context.</entry>
  175. </row>
  176. </tbody>
  177. </tgroup>
  178. </informaltable></para>
  179. </sect2>
  180. <sect2 id="Data_Types">
  181. <title>Data Types</title>
  182. <para><emphasis role="bold">Please see the BEGINC++ documentation for data
  183. type mapping.</emphasis></para>
  184. </sect2>
  185. <sect2 id="Passing_Set_Parameters_to_a_Service">
  186. <title>Passing Set Parameters<indexterm>
  187. <primary>Passing Set Parameters</primary>
  188. </indexterm><indexterm>
  189. <primary>Set Parameters</primary>
  190. </indexterm> to a Service</title>
  191. <para>Three types of set parameters are supported: INTEGER, REAL, and
  192. STRING<emphasis>n</emphasis>.</para>
  193. <para><emphasis role="bold">INTEGER<indexterm>
  194. <primary>INTEGER</primary>
  195. </indexterm></emphasis></para>
  196. <para>If you want to sum up all the elements in a set of integers with an
  197. external function, to declare the function in the SERVICE
  198. structure:</para>
  199. <programlisting> SetFuncLib := SERVICE
  200. INTEGER SumInt(SET OF INTEGER ss) :
  201. holertl,library='dab',entrypoint='rtlSumInt';
  202. END;
  203. x:= 3+4.5;
  204. SetFuncLib.SumInt([x, 11.79]); //passed two REAL numbers - it works
  205. </programlisting>
  206. <para>To define the external function, in the header (.h) file:</para>
  207. <programlisting>__int64 rtlSumInt(unsigned len, __int64 * a);</programlisting>
  208. <para>In the source code (.cpp) file:</para>
  209. <programlisting> __int64 rtlSumInt(unsigned len, __int64 * a) {
  210. __int64 sum = 0;
  211. for(unsigned i = 0; i &lt; len; i++) {
  212. sum += a[i];
  213. }
  214. return sum;
  215. }
  216. </programlisting>
  217. <para>The first parameter contains the length of the set, and the second
  218. parameter is an int array that holds the elements of the set. <emphasis
  219. role="bold">Note:</emphasis> In declaring the function in ECL, you can
  220. also have sets of INTEGER4, INTEGER2 and INTEGER1, but you need to change
  221. the type of the C function parameter, too. The relationship is:</para>
  222. <programlisting> INTEGER8 -- __int64
  223. INTEGER4 -- int
  224. INTEGER2 -- short
  225. INTEGER1 -- char
  226. </programlisting>
  227. <para><emphasis role="bold">REAL<indexterm>
  228. <primary>REAL</primary>
  229. </indexterm></emphasis></para>
  230. <para>If you want to sum up all the elements in a set of real
  231. numbers:</para>
  232. <para>To declare the function in the SERVICE structure<indexterm>
  233. <primary>SERVICE structure</primary>
  234. </indexterm>:</para>
  235. <programlisting> SetFuncLib := SERVICE
  236. REAL8 SumReal(SET OF REAL8 ss) :
  237. holertl,library='dab',entrypoint='rtlSumReal';
  238. END;
  239. INTEGER r1 := 10;
  240. r2 := 20.345;
  241. SetFuncLib.SumReal([r1, r2]);
  242. // intentionally passed an integer to the real set, it works too.
  243. </programlisting>
  244. <para>To define the external function, in the header (.h) file:</para>
  245. <para>double rtlSumReal(unsigned len, double * a);</para>
  246. <para>In the source code (.cpp) file:</para>
  247. <programlisting> double rtlSumReal(unsigned len, double * a) {
  248. double sum = 0;
  249. for(unsigned i = 0; i &lt; len; i++) {
  250. sum += a[i];
  251. }
  252. return sum;
  253. }
  254. </programlisting>
  255. <para>The first parameter contains the length of the set, and the second
  256. parameter is an array that holds the elements of the set.</para>
  257. <para><emphasis role="bold">Note:</emphasis> You can also declare the
  258. function in ECL as set of REAL4, but you need to change the parameter of
  259. the C function to float.</para>
  260. <para><emphasis role="bold">STRING</emphasis><emphasis
  261. role="bold">n<indexterm>
  262. <primary>STRINGn</primary>
  263. </indexterm></emphasis></para>
  264. <para>If you want to calculate the sum of the lengths of all the strings
  265. in a set, with the trailing blanks trimmed off:</para>
  266. <para>To declare the function in the SERVICE structure<indexterm>
  267. <primary>SERVICE structure</primary>
  268. </indexterm>:</para>
  269. <programlisting> SetFuncLib := SERVICE
  270. INTEGER SumCharLen(SET OF STRING20 ss) :
  271. holertl,library='dab',entrypoint='rtlSumCharLen';
  272. END;
  273. str1 := '1234567890'+'xxxx ';
  274. str2 := 'abc';
  275. SetFuncLib.SumCharLen([str1, str2]);
  276. </programlisting>
  277. <para>To define the external function, in the header (.h) file:</para>
  278. <programlisting>__int64 rtlSumCharLen(unsigned len, char a[ ][20]);</programlisting>
  279. <para>In the source code (.cpp) file:</para>
  280. <programlisting>__int64 rtlSumCharLen(unsigned len, char a[][20]) {
  281. __int64 sumtrimedlen = 0;
  282. for(unsigned i = 0; i &lt; len; i++) {
  283. for(int j = 20-1; j &gt;= 0; j—) {
  284. if(a[i][j] != ' ') {
  285. break;
  286. }
  287. a[i][j] = 0;
  288. }
  289. sumtrimedlen += j + 1;
  290. }
  291. return sumtrimedlen;
  292. } </programlisting>
  293. <para><emphasis role="bold">Note:</emphasis> In declaring the C function,
  294. we have two parameters for the set. The first parameter is the length of
  295. the set, the second parameter is char[][n] where n is the SAME as that in
  296. stringn. Eg., if the service is declared as "integer SumCharLen(set of
  297. string20)", then in the C function the parameter type must be char
  298. a[][20].</para>
  299. </sect2>
  300. <sect2 id="Plug-In_Requirements">
  301. <title>Plug-In Requirements</title>
  302. <para>Plug-ins require an exported function with the following signature
  303. under Windows:</para>
  304. <para>Extern "C" _declspec(dllexport) bool
  305. getECLPluginDefinition(ECLPluginDefinitionBlock *pb)</para>
  306. <para>The function must fill the passed structure with correct information
  307. for the features of the plug-in. The structure is defined as
  308. follows:</para>
  309. <para><emphasis role="bold">Warning:</emphasis> This function may be
  310. called without the plugin being loaded fully. It should not make any
  311. library calls or assume that dependent modules have been loaded or that it
  312. has been initialised. Specifically: "The system does not call DllMain for
  313. process and thread initialization and termination. Also, the system does
  314. not load additional executable modules that are referenced by the
  315. specified module."</para>
  316. <programlisting>Struct ECLPluginDefinitionBlock
  317. {
  318. Size_t size;
  319. //size of passed structure - filled in by the calling function
  320. Unsigned magicVersion ;
  321. // Filled in by .SO - must be PLUGIN_VERSION (1)
  322. Const char *moduleName;
  323. // Name of the module
  324. Const char *ECL;
  325. // ECL Service definition for non-HOLE applications
  326. Unsigned flags;
  327. // Type of plug-in - for user plugin use 1
  328. Const char *version ;
  329. // Text describing version of plugin - used in debugging
  330. Const char *description;
  331. // Text describing plugin
  332. } </programlisting>
  333. <para>To initialize information in a plug-in, use a global variable or
  334. class and it will be appropriately constructed/destructed when the plugin
  335. is loaded and unloaded.</para>
  336. </sect2>
  337. <sect2 id="Deployment">
  338. <title>Deployment</title>
  339. <para>External .SOs must be deployed to the /opt/HPCCSystems/plugins
  340. directory on each node of the target environment. If external data files
  341. are required, they should be either manually deployed to each node, or
  342. referenced from a network node (the latter requires hard-coding the
  343. address in the code for the .SO). Note that manually deployed files are
  344. not backed up with the standard SDS backup utilities.</para>
  345. </sect2>
  346. <sect2 id="Constraints">
  347. <title>Constraints</title>
  348. <para>The full set of data types is supported on the Data Refinery and
  349. Data Delivery Engines (Thor/Roxie/Doxie).</para>
  350. </sect2>
  351. <sect2 id="An_Example_Service">
  352. <title>An Example Service</title>
  353. <para>The following code example depicts an ECL system service (.SO)
  354. called examplelib that contains one entry point (<emphasis
  355. role="bold">stringfind</emphasis>). This is a slightly modified version of
  356. the Find function found in the Str standard library. This version is
  357. designed to work in the Data Refinery supercomputer.</para>
  358. </sect2>
  359. <sect2 id="ECL_definitions">
  360. <title>ECL definitions</title>
  361. <programlisting> EXPORT ExampleLib := SERVICE
  362. UNSIGNED4 StringFind(CONST STRING src,
  363. CONST STRING tofind,
  364. UNSIGNED4 instance )
  365. : c, pure,entrypoint='elStringFind';
  366. END; </programlisting>
  367. </sect2>
  368. <sect2 id="DLL_code_module">
  369. <title>.SO code module:</title>
  370. <para><programlisting>//******************************************************
  371. // hqlplugins.hpp : Defines standard values included
  372. in
  373. // the plugin header file.
  374. //******************************************************
  375. #ifndef __HQLPLUGIN_INCL
  376. #define __HQLPLUGIN_INCL
  377. #define PLUGIN_VERSION 1
  378. #define PLUGIN_IMPLICIT_MODULE 1
  379. #define PLUGIN_MODEL_MODULE 2
  380. #define PLUGIN_.SO_MODULE 4
  381. struct ECLPluginDefinitionBlock
  382. {
  383. size_t size;
  384. unsigned magicVersion;
  385. const char *moduleName;
  386. const char *ECL;
  387. const char *Hole;
  388. unsigned flags;
  389. const char *version;
  390. const char *description;
  391. };
  392. typedef bool (*EclPluginDefinition) (ECLPluginDefinitionBlock *);
  393. #endif //__HQLPLUGIN_INCL</programlisting></para>
  394. <programlisting>//******************************************************
  395. // examplelib.hpp : Defines standard values included in
  396. // the plugin code file.
  397. //******************************************************
  398. #ifndef EXAMPLELIB_INCL
  399. #define EXAMPLELIB_INCL
  400. #ifdef _WIN32
  401. #define EXAMPLELIB_CALL __cdecl
  402. #ifdef EXAMPLELIB_EXPORTS
  403. #define EXAMPLELIB_API __declspec(dllexport)
  404. #else
  405. #define EXAMPLELIB_API __declspec(dllimport)
  406. #endif
  407. #else
  408. #define EXAMPLELIB_CALL
  409. #define EXAMPLELIB_API
  410. #endif
  411. #include "hqlplugins.hpp"
  412. extern "C" {
  413. EXAMPLELIB_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb);
  414. EXAMPLELIB_API void setPluginContext(IPluginContext * _ctx);
  415. EXAMPLELIB_API unsigned EXAMPLELIB_CALL elStringFind(unsigned srcLen,
  416. const char * src, unsigned hitLen, const char * hit,
  417. unsigned instance);
  418. }
  419. #endif //EXAMPLELIB_INCL
  420. </programlisting>
  421. <para></para>
  422. <programlisting>//******************************************************
  423. // examplelib.cpp : Defines the plugin code.
  424. //******************************************************
  425. #include &lt;time.h&gt;
  426. #include &lt;stdlib.h&gt;
  427. #include &lt;string.h&gt;
  428. #include &lt;ctype.h&gt;
  429. #include "examplelib.hpp"
  430. #define EXAMPLELIB_VERSION "EXAMPLELIB 1.0.00"
  431. static const char * HoleDefinition = NULL;
  432. static const char * EclDefinition =
  433. "export ExampleLib := SERVICE\n"
  434. " string EchoString(const string src) : c, pure,fold,entrypoint='elEchoString'; \n"
  435. "END;";
  436. EXAMPLELIB_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
  437. {
  438. // Warning: This function may be called without the plugin being loaded fully.
  439. // It should not make any library calls or assume that dependent modules
  440. // have been loaded or that it has been initialised.
  441. //
  442. // Specifically: "The system does not call DllMain for process and thread
  443. // initialization and termination. Also, the system does not load
  444. // additional executable modules that are referenced by the specified module."
  445. if (pb-&gt;size != sizeof(ECLPluginDefinitionBlock))
  446. return false;
  447. pb-&gt;magicVersion = PLUGIN_VERSION;
  448. pb-&gt;version = EXAMPLELIB_VERSION " $Revision: 62376 $";
  449. pb-&gt;moduleName = "lib_examplelib";
  450. pb-&gt;ECL = EclDefinition;
  451. pb-&gt;Hole = HoleDefinition;
  452. pb-&gt;flags = PLUGIN_IMPLICIT_MODULE;
  453. pb-&gt;description = "ExampleLib example services library";
  454. return true;
  455. }
  456. namespace nsExamplelib {
  457. IPluginContext * parentCtx = NULL;
  458. }
  459. using namespace nsExamplelib;
  460. EXAMPLELIB_API void setPluginContext(IPluginContext * _ctx) { parentCtx = _ctx; }
  461. //-------------------------------------------------------------------------------------------------------------------------------------------
  462. EXAMPLELIB_API unsigned EXAMPLELIB_CALL elStringFind(unsigned srcLen,
  463. const char * src, unsigned hitLen, const char * hit,
  464. unsigned instance)
  465. {
  466. tgt = (char *)CTXMALLOC(parentCtx, srcLen);
  467. memcpy(tgt,src,srcLen);
  468. tgtLen = srcLen;
  469. }
  470. </programlisting>
  471. </sect2>
  472. </sect1>