AEs that are both local and remote
For a simple local-only AE that does not use shapers, a direct initialize call can be used to get a data handle, such as the C API nzaeInitialize for a function AE and nzaeAggInitialize for an aggregate AE. However, if either shapers or remote AEs are being supported, the AE application must be able to determine how it is invoked.
All-In-One Approach
This example shows the general process for making a data connection. The language adapters have functionality to partially automate this procedure.
if (isLocal)
{
dataConn = getLocalApi
// dataConn is the data connection
switch (dataConn.apiType)
{
case FUNCTION: // Table or Scalar Function
run(dataConn.function)
close(dataConn.function)
break
case AGGREAGATE: // Aggregate Function
run(dataConn.aggregate)
close(dataConn.aggregate)
break
case SHAPER: // Table Shaper or Scalar Sizer
run(dataConn.shaper)
close(dataConn.shaper)
break
}
}
else
{
// Remote AE
connPoint = createConnectionPoint
listener = createListener(connPoint)
// listener is the notification connection
for (;;)
{
dataConn = acceptRemoteApi(listener)
switch (dataConn.apiType)
{
case FUNCTION: // Table or Scalar Function
run(dataConn.function)
close(dataConn.function)
break
case AGGREGATE: // Aggregate Function
run(dataConn.aggregate)
close(dataConn.aggregate)
break
case SHAPER: // Table Shaper or Scalar Sizer
run(dataConn.shaper)
close(dataConn.shaper)
break
}
}
// the following code may not be reached
close(listener)
close(connPoint)
}
Forking Approach
When using a programming language such as Java, which has solid thread support, a threaded approach is recommended. For languages without thread support or with limited thread support, the forking approach works well.
For a programming language that can support both threading and forking approaches, such as C and C++, the requirements of the application or support libraries determine the approach.
When using the forking approach, a data connection can be made under the remote AE. Instead of accepting an API, an AE environment can be accepted. An AE environment is not a data connection but can be used in an initialize call to create a data connection. To fork and use a data connection is not valid; however, to fork and use an AE environment is valid. An AE environment can be first serialized to bytes, then unserialized, and then be used to create a data connection. This example uses an AE environment with fork to run a data request in a new process:
for (;;)
{
aeEnv = acceptRemoteEnvironment(listener)
fork
if(parent)
{
// in parent process
close(aeEnv)
continue loop
}
// in child process
freeResources(listener)
close(connPoint)
switch (aeEnv.apiType)
{
case FUNCTION: // Table or Scalar Function
conn = initializeFunctionAE(aeEnv)
run(conn)
close(conn)
exit
case AGGREGATE: // Aggregate Function
conn = initializeAggregateAE(aeEnv)
run(conn)
close(conn)
close(env)
exit
case SHAPER: // Table Shaper or Scalar Sizer
conn = initializeShaperAE(aeEnv)
run(conn)
close(conn)
exit
}
}
}
When using Linux fork, avoid creating "zombie" Linux processes by either ignoring signal SIGCHLD or handling the signal and waiting on the child processes. Waiting on the child processes outside the signal handler is not recommended since the parent could become blocked and not handle subsequent AE notifications. When possible, ignoring the signal is the better approach. If the SIGCHLD signal is handled, care must be taken so that no child processes are missed and the parent does not become blocked.