123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
- <sect1 id="External_Service_Implementation">
- <title>External Service Implementation</title>
- <para>ECL external system services<indexterm>
- <primary>external system services</primary>
- </indexterm><indexterm>
- <primary>External Service</primary>
- </indexterm> are implemented as exported functions in a .SO (Shared
- Object)<indexterm>
- <primary>.SO</primary>
- </indexterm><indexterm>
- <primary>Shared Object</primary>
- </indexterm>. An ECL system service .SO can contain one or more services
- and (possibly) a single .SO initialization routine. All system service
- libraries must be thread safe.</para>
- <para>All exported functions in the .SO (hereafter referred to as "entry
- points") must adhere to certain calling and naming conventions. First, entry
- points must use the "C" naming convention. That is, function name decoration
- (like that used by C++) is not allowed.</para>
- <para>Second, the storage class of __declspec(dllexport) and declaration
- type _cdecl need to be declared for Windows/Microsoft C++ applications.
- Typically, SERVICE_CALL is defined as _declspec(dllexport) and SERVICE_API
- is defined as _cdecl for Windows, and left as nulls for Linux. For
- example:</para>
- <programlisting>Extern "C" _declspec(dllexport) unsigned _cdecl Countchars(const unsigned len, const char *string)</programlisting>
- <para><emphasis role="bold">Note</emphasis>: The use of an external SERVICE
- may be restricted to signed modules. See Code Signing in the ECL
- Programmer's Guide.</para>
- <sect2 id="DLL_Initialization">
- <title>.SO Initialization</title>
- <para>The following is an example prototype for an ECL (.SO) system
- service initialization routine:</para>
- <programlisting>extern "C" void stdcall <functionName> (IEclWorkUnit *w);</programlisting>
- <para>The IEclWorkUnit is transparent to the application, and can be
- declared as Struct IEclWorkUnit; or simply referred to as a void *.</para>
- <para>In addition, an initialization routine should retain a reference to
- its "Work Unit." Typically, a global variable is used to retain this
- value. For example:</para>
- <programlisting>IEclWorkUnit *workUnit;
- // global variable to hold the Work Unit reference
-
- extern "C" void SERVICE_API myInitFunction (IEclWorkUnit *w)
- {
- workUnit = w; // retain reference to "Work Unit"
- }
- </programlisting>
- </sect2>
- <sect2 id="Entry_Points">
- <title>Entry Points</title>
- <para>Entry points have the same definition requirements as initialization
- routines. However, unlike initialization routines, entry points can return
- a value. Valid return types are listed below. The following is an example
- of an entry point:</para>
- <programlisting>extern "C" __int64 SERVICE_API PrnLog(unsigned long len, const char *val)
- {
- }
- </programlisting>
- </sect2>
- <sect2 id="SERVICE_Structure_external">
- <title>SERVICE Structure - external<indexterm>
- <primary>SERVICE Structure</primary>
- </indexterm></title>
- <para>For each system service defined, a corresponding ECL function
- prototype must be declared (see <emphasis role="bold">SERVICE
- Structure</emphasis>).</para>
- <programlisting> servicename := SERVICE
- functionname(parameter list) [: keyword = value];
- END;
-
- For example:
- email := SERVICE
- simpleSend(STRING address, STRING template, STRING subject)
- : LIBRARY='ecl2cw', INITFUNCTION='initEcl2Cw';
- END;
- </programlisting>
- </sect2>
- <sect2 id="Keywords">
- <title>Keywords<indexterm>
- <primary>Service Function Keywords</primary>
- </indexterm></title>
- <para>This is the list of valid keywords for use in service function
- prototypes:</para>
- <para><informaltable colsep="1" frame="all" rowsep="1">
- <tgroup cols="2">
- <colspec colwidth="115.95pt" />
- <colspec />
- <tbody>
- <row>
- <entry><emphasis>LIBRARY</emphasis></entry>
- <entry>Indicates the name of the .SO module an entry point is
- defined in.</entry>
- </row>
- <row>
- <entry><emphasis>ENTRYPOINT</emphasis></entry>
- <entry>Specifies a name for the entry point. By default, the
- name of the entry point is the function name.</entry>
- </row>
- <row>
- <entry><emphasis>INITFUNCTION</emphasis></entry>
- <entry>Specifies the name of the initialization routine defined
- in the module containing the entry point. Currently, the
- initialization function is called once.</entry>
- </row>
- <row>
- <entry><emphasis>INCLUDE<indexterm>
- <primary>INCLUDE</primary>
- </indexterm></emphasis></entry>
- <entry>Indicates the function prototype is in the specified
- include file, so the generated CPP must #include that file. If
- INCLUDE is not specified, the C++ prototype is generated from
- the ECL function definition.</entry>
- </row>
- <row>
- <entry><emphasis>C</emphasis></entry>
- <entry>Indicates the generated C++ prototype is enclosed within
- an extern "C" rather than just extern.</entry>
- </row>
- <row>
- <entry><emphasis>PURE<indexterm>
- <primary>PURE</primary>
- </indexterm></emphasis></entry>
- <entry>Indicates the function returns the same result every time
- you call it with the same parameters and has no side effects.
- This allows the optimizer to make more efficient calls to the
- function in some cases.</entry>
- </row>
- <row>
- <entry><emphasis>ONCE<indexterm>
- <primary>ONCE</primary>
- </indexterm></emphasis></entry>
- <entry>Indicates the function has no side effects and is
- evaluated at query execution time, even if the parameters are
- constant. This allows the optimizer to make more efficient calls
- to the function in some cases.</entry>
- </row>
- <row>
- <entry><emphasis>FOLD<indexterm>
- <primary>FOLD</primary>
- </indexterm></emphasis></entry>
- <entry>Specifies that the function is evaluated at compile time
- if all parameters are constants. Specifying FOLD to the SERVICE
- applys it to all function definitions in the service - in such
- cases NOFOLD may be useful to override this default for
- individual functions that are not suitable for constant
- folding.</entry>
- </row>
- <row>
- <entry><emphasis>NOFOLD<indexterm>
- <primary>NOFOLD</primary>
- </indexterm></emphasis></entry>
- <entry>Specifies that the service is not suitable for constant
- folding.</entry>
- </row>
- <row>
- <entry><emphasis>ACTION</emphasis></entry>
- <entry>Indicates the function has side effects and requires the
- optimizer to not remove calls to the function.</entry>
- </row>
- <row>
- <entry><emphasis>CONTEXT</emphasis></entry>
- <entry>Internal use, only. Indicates an extra internal context
- parameter (ICodeContext *) is passed to the function. This must
- be the first function parameter.</entry>
- </row>
- <row>
- <entry><emphasis>GLOBALCONTEXT</emphasis></entry>
- <entry>Internal use, only. Same as CONTEXT, but there are
- restrictions on where the function can be used (for example, not
- in a TRANSFORM).</entry>
- </row>
- <row>
- <entry><emphasis>CTXMETHOD</emphasis></entry>
- <entry>Internal use, only. Indicates the function is actually a
- method of the internal code context.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable></para>
- </sect2>
- <sect2 id="Data_Types">
- <title>Data Types</title>
- <para><emphasis role="bold">Please see the BEGINC++ documentation for data
- type mapping.</emphasis></para>
- </sect2>
- <sect2 id="Passing_Set_Parameters_to_a_Service">
- <title>Passing Set Parameters<indexterm>
- <primary>Passing Set Parameters</primary>
- </indexterm><indexterm>
- <primary>Set Parameters</primary>
- </indexterm> to a Service</title>
- <para>Three types of set parameters are supported: INTEGER, REAL, and
- STRING<emphasis>n</emphasis>.</para>
- <para><emphasis role="bold">INTEGER<indexterm>
- <primary>INTEGER</primary>
- </indexterm></emphasis></para>
- <para>If you want to sum up all the elements in a set of integers with an
- external function, to declare the function in the SERVICE
- structure:</para>
- <programlisting> SetFuncLib := SERVICE
- INTEGER SumInt(SET OF INTEGER ss) :
- holertl,library='dab',entrypoint='rtlSumInt';
- END;
- x:= 3+4.5;
- SetFuncLib.SumInt([x, 11.79]); //passed two REAL numbers - it works
- </programlisting>
- <para>To define the external function, in the header (.h) file:</para>
- <programlisting>__int64 rtlSumInt(unsigned len, __int64 * a);</programlisting>
- <para>In the source code (.cpp) file:</para>
- <programlisting> __int64 rtlSumInt(unsigned len, __int64 * a) {
- __int64 sum = 0;
- for(unsigned i = 0; i < len; i++) {
- sum += a[i];
- }
- return sum;
- }
- </programlisting>
- <para>The first parameter contains the length of the set, and the second
- parameter is an int array that holds the elements of the set. <emphasis
- role="bold">Note:</emphasis> In declaring the function in ECL, you can
- also have sets of INTEGER4, INTEGER2 and INTEGER1, but you need to change
- the type of the C function parameter, too. The relationship is:</para>
- <programlisting> INTEGER8 -- __int64
- INTEGER4 -- int
- INTEGER2 -- short
- INTEGER1 -- char
- </programlisting>
- <para><emphasis role="bold">REAL<indexterm>
- <primary>REAL</primary>
- </indexterm></emphasis></para>
- <para>If you want to sum up all the elements in a set of real
- numbers:</para>
- <para>To declare the function in the SERVICE structure<indexterm>
- <primary>SERVICE structure</primary>
- </indexterm>:</para>
- <programlisting> SetFuncLib := SERVICE
- REAL8 SumReal(SET OF REAL8 ss) :
- holertl,library='dab',entrypoint='rtlSumReal';
- END;
-
- INTEGER r1 := 10;
- r2 := 20.345;
- SetFuncLib.SumReal([r1, r2]);
- // intentionally passed an integer to the real set, it works too.
- </programlisting>
- <para>To define the external function, in the header (.h) file:</para>
- <para>double rtlSumReal(unsigned len, double * a);</para>
- <para>In the source code (.cpp) file:</para>
- <programlisting> double rtlSumReal(unsigned len, double * a) {
- double sum = 0;
- for(unsigned i = 0; i < len; i++) {
- sum += a[i];
- }
- return sum;
- }
- </programlisting>
- <para>The first parameter contains the length of the set, and the second
- parameter is an array that holds the elements of the set.</para>
- <para><emphasis role="bold">Note:</emphasis> You can also declare the
- function in ECL as set of REAL4, but you need to change the parameter of
- the C function to float.</para>
- <para><emphasis role="bold">STRING</emphasis><emphasis
- role="bold">n<indexterm>
- <primary>STRINGn</primary>
- </indexterm></emphasis></para>
- <para>If you want to calculate the sum of the lengths of all the strings
- in a set, with the trailing blanks trimmed off:</para>
- <para>To declare the function in the SERVICE structure<indexterm>
- <primary>SERVICE structure</primary>
- </indexterm>:</para>
- <programlisting> SetFuncLib := SERVICE
- INTEGER SumCharLen(SET OF STRING20 ss) :
- holertl,library='dab',entrypoint='rtlSumCharLen';
- END;
- str1 := '1234567890'+'xxxx ';
- str2 := 'abc';
- SetFuncLib.SumCharLen([str1, str2]);
- </programlisting>
- <para>To define the external function, in the header (.h) file:</para>
- <programlisting>__int64 rtlSumCharLen(unsigned len, char a[ ][20]);</programlisting>
- <para>In the source code (.cpp) file:</para>
- <programlisting>__int64 rtlSumCharLen(unsigned len, char a[][20]) {
- __int64 sumtrimedlen = 0;
- for(unsigned i = 0; i < len; i++) {
- for(int j = 20-1; j >= 0; j—) {
- if(a[i][j] != ' ') {
- break;
- }
- a[i][j] = 0;
- }
- sumtrimedlen += j + 1;
- }
- return sumtrimedlen;
- } </programlisting>
- <para><emphasis role="bold">Note:</emphasis> In declaring the C function,
- we have two parameters for the set. The first parameter is the length of
- the set, the second parameter is char[][n] where n is the SAME as that in
- stringn. Eg., if the service is declared as "integer SumCharLen(set of
- string20)", then in the C function the parameter type must be char
- a[][20].</para>
- </sect2>
- <sect2 id="Plug-In_Requirements">
- <title>Plug-In Requirements</title>
- <para>Plug-ins require an exported function with the following signature
- under Windows:</para>
- <para>Extern "C" _declspec(dllexport) bool
- getECLPluginDefinition(ECLPluginDefinitionBlock *pb)</para>
- <para>The function must fill the passed structure with correct information
- for the features of the plug-in. The structure is defined as
- follows:</para>
- <para><emphasis role="bold">Warning:</emphasis> This function may be
- called without the plugin being loaded fully. It should not make any
- library calls or assume that dependent modules have been loaded or that it
- has been initialised. Specifically: "The system does not call DllMain for
- process and thread initialization and termination. Also, the system does
- not load additional executable modules that are referenced by the
- specified module."</para>
- <programlisting>Struct ECLPluginDefinitionBlock
- {
- Size_t size;
- //size of passed structure - filled in by the calling function
- Unsigned magicVersion ;
- // Filled in by .SO - must be PLUGIN_VERSION (1)
- Const char *moduleName;
- // Name of the module
- Const char *ECL;
- // ECL Service definition for non-HOLE applications
- Unsigned flags;
- // Type of plug-in - for user plugin use 1
- Const char *version ;
- // Text describing version of plugin - used in debugging
- Const char *description;
- // Text describing plugin
- } </programlisting>
- <para>To initialize information in a plug-in, use a global variable or
- class and it will be appropriately constructed/destructed when the plugin
- is loaded and unloaded.</para>
- </sect2>
- <sect2 id="Deployment">
- <title>Deployment</title>
- <para>External .SOs must be deployed to the /opt/HPCCSystems/plugins
- directory on each node of the target environment. If external data files
- are required, they should be either manually deployed to each node, or
- referenced from a network node (the latter requires hard-coding the
- address in the code for the .SO). Note that manually deployed files are
- not backed up with the standard SDS backup utilities.</para>
- </sect2>
- <sect2 id="Constraints">
- <title>Constraints</title>
- <para>The full set of data types is supported on the Data Refinery and
- Data Delivery Engines (Thor/Roxie/Doxie).</para>
- </sect2>
- <sect2 id="An_Example_Service">
- <title>An Example Service</title>
- <para>The following code example depicts an ECL system service (.SO)
- called examplelib that contains one entry point (<emphasis
- role="bold">stringfind</emphasis>). This is a slightly modified version of
- the Find function found in the Str standard library. This version is
- designed to work in the Data Refinery supercomputer.</para>
- </sect2>
- <sect2 id="ECL_definitions">
- <title>ECL definitions</title>
- <programlisting> EXPORT ExampleLib := SERVICE
- UNSIGNED4 StringFind(CONST STRING src,
- CONST STRING tofind,
- UNSIGNED4 instance )
- : c, pure,entrypoint='elStringFind';
- END; </programlisting>
- </sect2>
- <sect2 id="DLL_code_module">
- <title>.SO code module:</title>
- <para><programlisting>//******************************************************
- // hqlplugins.hpp : Defines standard values included
- in
- // the plugin header file.
- //******************************************************
- #ifndef __HQLPLUGIN_INCL
- #define __HQLPLUGIN_INCL
-
- #define PLUGIN_VERSION 1
-
- #define PLUGIN_IMPLICIT_MODULE 1
- #define PLUGIN_MODEL_MODULE 2
- #define PLUGIN_.SO_MODULE 4
-
- struct ECLPluginDefinitionBlock
- {
- size_t size;
- unsigned magicVersion;
- const char *moduleName;
- const char *ECL;
- const char *Hole;
- unsigned flags;
- const char *version;
- const char *description;
- };
-
- typedef bool (*EclPluginDefinition) (ECLPluginDefinitionBlock *);
-
- #endif //__HQLPLUGIN_INCL</programlisting></para>
- <programlisting>//******************************************************
- // examplelib.hpp : Defines standard values included in
- // the plugin code file.
- //******************************************************
- #ifndef EXAMPLELIB_INCL
- #define EXAMPLELIB_INCL
-
- #ifdef _WIN32
- #define EXAMPLELIB_CALL __cdecl
- #ifdef EXAMPLELIB_EXPORTS
- #define EXAMPLELIB_API __declspec(dllexport)
- #else
- #define EXAMPLELIB_API __declspec(dllimport)
- #endif
- #else
- #define EXAMPLELIB_CALL
- #define EXAMPLELIB_API
- #endif
-
- #include "hqlplugins.hpp"
-
- extern "C" {
- EXAMPLELIB_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb);
- EXAMPLELIB_API void setPluginContext(IPluginContext * _ctx);
- EXAMPLELIB_API unsigned EXAMPLELIB_CALL elStringFind(unsigned srcLen,
- const char * src, unsigned hitLen, const char * hit,
- unsigned instance);
- }
-
- #endif //EXAMPLELIB_INCL
- </programlisting>
- <para></para>
- <programlisting>//******************************************************
- // examplelib.cpp : Defines the plugin code.
- //******************************************************
- #include <time.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include "examplelib.hpp"
- #define EXAMPLELIB_VERSION "EXAMPLELIB 1.0.00"
- static const char * HoleDefinition = NULL;
- static const char * EclDefinition =
- "export ExampleLib := SERVICE\n"
- " string EchoString(const string src) : c, pure,fold,entrypoint='elEchoString'; \n"
- "END;";
- EXAMPLELIB_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
- {
- // Warning: This function may be called without the plugin being loaded fully.
- // It should not make any library calls or assume that dependent modules
- // have been loaded or that it has been initialised.
- //
- // Specifically: "The system does not call DllMain for process and thread
- // initialization and termination. Also, the system does not load
- // additional executable modules that are referenced by the specified module."
- if (pb->size != sizeof(ECLPluginDefinitionBlock))
- return false;
- pb->magicVersion = PLUGIN_VERSION;
- pb->version = EXAMPLELIB_VERSION " $Revision: 62376 $";
- pb->moduleName = "lib_examplelib";
- pb->ECL = EclDefinition;
- pb->Hole = HoleDefinition;
- pb->flags = PLUGIN_IMPLICIT_MODULE;
- pb->description = "ExampleLib example services library";
- return true;
- }
- namespace nsExamplelib {
- IPluginContext * parentCtx = NULL;
- }
- using namespace nsExamplelib;
- EXAMPLELIB_API void setPluginContext(IPluginContext * _ctx) { parentCtx = _ctx; }
- //-------------------------------------------------------------------------------------------------------------------------------------------
- EXAMPLELIB_API unsigned EXAMPLELIB_CALL elStringFind(unsigned srcLen,
- const char * src, unsigned hitLen, const char * hit,
- unsigned instance)
- {
- tgt = (char *)CTXMALLOC(parentCtx, srcLen);
- memcpy(tgt,src,srcLen);
- tgtLen = srcLen;
- }
- </programlisting>
- </sect2>
- </sect1>
|