Dependencies
To begin writing C++ UDFs, access to the Kinetica C++ UDF API is required. In default Kinetica installations, the C++ UDF API is located in the/opt/gpudb/udf/api/cpp directory.
If developing UDFs without a local Kinetica installation, the API can be
downloaded from the C++ UDF API repo on GitHub.
After downloading, see the README.md in the UDF API directory created
for further setup instructions.
The UDF C++ API consists of two files: Proc.hpp & Proc.cpp.
These need to be included in the make process and the header file,
Proc.hpp needs to be included in the UDF source code. There are no
external dependencies beyond the C++ standard library.
To take advantage of GPU processing within a UDF, the CUDA Toolkit must be
downloaded & installed from the
Nvidia Developer Zone.
Initializing
A UDF must get a handle toProcData using kinetica::ProcData::get().
This will parse the primary control file and set up all the necessary
structures. It will return a kinetica::ProcData* instance, which is used to
access everything else. All configuration information is cached, so repeated
calls to kinetica::ProcData::get() will not reload any configuration files.
When you get a handle to
ProcData, the handle is actually
to the data given to that instance (OS process) of the UDF on the
Kinetica host; therefore, there will be a ProcData handle for every
instance of the UDF on your Kinetica hostColumn Types
Unlike the other Kinetica APIs, the UDF C++ API does not process data using records or schemas, operating in terms of columns of data instead. The raw column values returned closely map to the data types used in the tables being accessed:Numeric
String
Date/Time
Binary
While
CharN column values are arrays of N chars, there is a template
class, kinetica::CharN<N>, that makes accessing these easier (it does
automatic to and from string conversions and provides accessors that make the
chars appear to be in the expected order). To access column values, use:
No type-checking is performed, so the correct type for the column
must be used in this call.
null, use:
getValue, getVarString, or getVarBytes on a null value
causes undefined behavior, so always check first. Calling isNull on a
non-nullable column will always return false.
For debugging purposes, there is also a column.toString(n) method that
converts a specified column value to a string, regardless of type.
Reading Input Data
Accessing Input Values
TheInputDataSet object returned from procData->getInputData() contains
the InputTable object, which in turn contains InputColumn, holding the
actual data set. Tables and columns can be accessed by index or by name. For
example, given a customer table at InputDataSet index 5 and a
name column at that InputTable’s index 1, either of the following
calls will retrieve the column values associated with customer.name:
Request Info Keys
The request info keys are returned from callingproc_data.request_info.
These keys include a variety of details about the executing UDF from the
request information map made available to each running UDF.
General Information
CUDA Information
When executing UDFs that utilize CUDA, additional request information is returned.Data Segment Information
Data is passed into UDFs in segments. Each segment consists of the entirety of the data on a single TOM and is processed by the UDF instance executing on that TOM. Thus, there is a 1-to-1 mapping of data segment and executing UDF instance, though this relationship may change in the future. Running the same UDF multiple times should result in the same set of segments, assuming the same environment and system state across runs.Kinetica API Connection Parameters
These can be used to connect back to Kinetica using the regular API endpoint calls. Use with caution in distributed UDFs, particularly in large clusters, to avoid overwhelming the head node. Also note, multi-head ingest may not work from a UDF in some cases without overriding the worker URLs to use internal IP addresses.Since
username and password are randomly-generated
temporary credentials, for security reasons, they should not be
printed or output to logs.Writing Output Data
To output data to a table, the size of the table must be set in order to allocate enough space in all of the columns to hold the correct number of values. To do this, call:Setting Output Values
TheOutputDataSet object returned from procData.getOutputData() contains
the OutputTable object, which in turn contains OutputColumn, holding the
actual data set. Tables and columns are accessed the same way as
InputDataSet:
- appending a series of values to each table column
- setting table column values by index
OutputColumn of the
OutputTable:
-
Appending (required for variable-length data)
appendValue(value)appendVarString(value)appendVarBytes(value)appendNull()
-
Setting by Index (non-variable length data only)
setValue(n, value)setNull(n, value)
Status Reporting
TheprocData->getStatus() property can be set to a string value to help
convey status information during UDF execution, e.g.,
procData->getStatus("25% complete"). The /show/proc/status
endpoint will return any status messages set for each data segment — one data
segment per processing node if in distributed mode, or one data segment total
in non-distributed mode. These messages are subject to the following scenarios:
-
If the user-provided UDF code is executing and has set a status message,
/show/proc/statuswill return the last message that was set -
If the user-provided UDF code finishes executing successfully, the status
message is cleared
The UDF may not show as “complete” yet since any data written by the UDF (in distributed mode) still has to be inserted into the database, but the status set by the UDF code isn’t relevant to this process
-
If the UDF is killed while executing user-provided UDF code,
/show/proc/statuswill return the last message that was set -
If the user-provided UDF code errors out,
/show/proc/statuswill return the error message and the last status message that was set in parentheses
Complete
The UDF must finish with a call toprocData->complete(). This writes out
some final control information to indicate that the UDF completed
successfully.
If this call is not made, the database will assume that the UDF
didn’t finish and will return an error to the caller.
Logging
Any output from the UDF to is written to two places:- The system log file on the head node
- The /opt/gpudb/core/logs/gpudb.log file local to the processing node container