Programming in C

Sample Program

In order to help understand a lot of the description below, you can download the wordfreq.c sample program, with a reference input file and corresponding reference output file and compile it. Here are some copy pastable instructions. The diff exit code should be zero, as the files should be identical. For the following example, you will need to use the bash shell, have git, diff and a C compiler (gcc here) installed.

mkdir test
cd test
git clone https://gitlab.com/YottaDB/DB/YDBTest
source /usr/local/etc/ydb_env_set
gcc `pkg-config --cflags yottadb` wordfreq.c `pkg-config --libs yottadb` -o wordfreq
./wordfreq < YDBTest/simpleapi/outref/wordfreq_input.txt > wordfreq.out
diff wordfreq.out YDBTest/simpleapi/outref/wordfreq_output.txt
echo $?

Symbolic Constants

The libyottadb.h file defines several symbolic constants, which are one of the following types:

  • Function Return Codes, which in turn are one of:

    • Normal Return Codes

    • Error Return Codes

  • Limits

  • Other

Symbolic constants all fit within the range of a C int.

Function Return Codes

Return codes from calls to YottaDB are usually of type int and occasionally other types. Normal return codes are non-negative (greater than or equal to zero); error return codes are negative.

Normal Return Codes

Symbolic constants for normal return codes have YDB_ prefixes other than YDB_ERR_.

YDB_LOCK_TIMEOUT

This return code from lock acquisition functions indicates that the specified timeout was reached without the requested locks being acquired.

YDB_OK

This the standard return code of all functions following successful execution.

YDB_TP_RESTART

Return code to YottaDB from an application function that implements a transaction to indicate that it wishes YottaDB to restart the transaction, or by a YottaDB function invoked within a transaction to its caller that the database engine has detected that it will be unable to commit the transaction and will need to restart. Application code designed to be executed within a transaction should be written to recognize this return code and in turn perform any cleanup required and return to the YottaDB ydb_tp_s() / ydb_tp_st() invocation from which it was called. See Transaction Processing for a discussion of restarts.

YDB_TP_ROLLBACK

Return code to YottaDB from an application function that implements a transaction, and in turn returned to the caller indicating that the transaction was not committed.

Error Return Codes

Symbolic constants for error codes returned by calls to YottaDB are prefixed with YDB_ERR_ and are all less than zero. The symbolic constants below are not a complete list of all error messages that YottaDB functions can return — error return codes can indicate system errors and database errors, not just application errors. A process that receives a negative return code, including one not listed here, can call ydb_get_s() / ydb_get_st() to get the value of $zstatus.

Error messages can be raised by the YottaDB runtime system or by the underlying operating system.

Remember that the error codes returned by YottaDB functions are the negated numeric values of the error codes above.

YDB_ERR_CALLINAFTERXIT

A YottaDB function was called after ydb_exit() was called.

YDB_ERR_FATALERROR1

A fatal error occurred. The process is generating a core dump and terminating. As a process cannot receive a fatal error code, this error appears in the syslog.

YDB_ERR_FATALERROR2

A fatal error occurred. The process is terminating without generating a core dump. As a process cannot receive a fatal error code, this error appears in the syslog.

YDB_ERR_GVUNDEF

No value exists at a requested global variable node.

YDB_ERR_INVNAMECOUNT

A namecount parameter has an invalid value.

YDB_ERR_INSUFFSUBS

A call to ydb_node_next_s() / ydb_node_next_st() or ydb_node_previous_s() / ydb_node_previous_st() did not provide enough parameters for the return values. Note that as the number of parameters is a count, when array subscripts start at 0, an array subscript of n corresponds to n+1 parameters.

YDB_ERR_INVSTRLEN

A buffer provided by the caller is not long enough for a string to be returned, or the length of a string passed as a parameter exceeds YDB_MAX_STR. In the event the return code is YDB_ERR_INVSTRLEN and if *xyz is a ydb_buffer_t structure whose xyz->len_alloc indicates insufficient space, then xyz->len_used is set to the size required of a sufficiently large buffer. In this case the len_used field of a ydb_buffer_t structure is greater than the len_alloc field, and the caller is responsible for correcting the xyz->len_used field.

YDB_ERR_INVSVN

A special variable name provided by the caller is invalid.

YDB_ERR_INVVARNAME

A variable name provided by the caller is invalid.

YDB_ERR_KEY2BIG

The length of a global variable name and subscripts exceeds the limit configured for the database region to which it is mapped.

YDB_ERR_LVUNDEF

No value exists at a requested local variable node.

YDB_ERR_MAXNRSUBSCRIPTS

The number of subscripts specified in the call exceeds YDB_MAX_SUBS.

YDB_ERR_MINNRSUBSCRIPTS

The number of subscripts cannot be negative.

YDB_ERR_NAMECOUNT2HI

The number of variable names specified to ydb_delete_excl_s() / ydb_delete_excl_st() or ydb_tp_s() / ydb_tp_st() exceeded the YDB_MAX_NAMES.

YDB_ERR_NODEEND

In the event a call to ydb_node_next_s() / ydb_node_next_st(), ydb_node_previous_s() / ydb_node_previous_st(), ydb_subscript_next_s() / ydb_subscript_next_st(), or ydb_subscript_previous_s() / ydb_subscript_previous_st() wish to report that there no further nodes/subscripts in their traversals, they return this value.

YDB_NOTOK

ydb_file_name_to_id() / ydb_file_name_to_id_t() was called with a NULL pointer to a filename.

YDB_ERR_NUMOFLOW

A ydb_incr_s() / ydb_incr_st() operation resulted in a numeric overflow.

YDB_ERR_PARAMINVALID

A parameter provided by the caller is invalid.

YDB_ERR_SIMPLEAPINEST

An attempt was made to nest Simple API calls, which cannot be nested.

YDB_ERR_SUBSARRAYNULL

The subs_used parameter of a function is greater than zero, but the subsarray parameter is a NULL pointer.

YDB_ERR_SVNOSET

The application inappropriately attempted to modify the value of an intrinsic special variable such as an attempt to modify $trestart using ydb_set_s() / ydb_set_st().

YDB_ERR_TIME2LONG

This return code indicates that a value greater than YDB_MAX_TIME_NSEC was specified for a time duration.

YDB_ERR_TPTIMEOUT

This return code from ydb_tp_s() / ydb_tp_st() indicates that the transaction took too long to commit.

YDB_ERR_UNIMPLOP

An operation that is not supported for an intrinsic special variable – of the Simple API functions only ydb_get_s() / ydb_get_st() and ydb_set_s() / ydb_set_st() are supported – was attempted on an intrinsic special variable.

YDB_ERR_VARNAME2LONG

A variable name length exceeds YottaDB's limit.

Limits

Symbolic constants for limits are prefixed with YDB_MAX_ or YDB_MIN_.

YDB_MAX_IDENT

The maximum space in bytes required to store a complete variable name, not including the preceding caret for a global variable. Therefore, when allocating space for a string to hold a global variable name, add 1 for the caret.

YDB_MAX_M_LINE_LEN

The maximum M source code line length, in bytes.

YDB_MAX_NAMES

The maximum number of variable names that can be passed to ydb_delete_excl_s() / ydb_delete_excl_st() or ydb_tp_s() / ydb_tp_st().

YDB_MAX_STR

The maximum length of a string (or blob) in bytes. A caller to ydb_get_s() / ydb_get_st() whose *ret_value parameter provides a buffer of YDB_MAX_STR will never get a YDB_ERR_INVSTRLEN error.

YDB_MAX_SUBS

The maximum number of subscripts for a local or global variable.

YDB_MAX_TIME_NSEC

The maximum value in nanoseconds that an application can instruct libyottab to wait, e.g., until the process is able to acquire locks it needs before timing out, or for ydb_hiber_start(). Note that even if timer resolution is in nanoseconds, the accuracy is always determined by the underlying hardware and operating system, as well as factors such as system load.

YDB_MAX_YDBERR

The absolute (positive) value of any YottaDB function error return code. If the absolute value of an error return code is greater than YDB_MAX_YDBERR, then it is an error code from elsewhere, e.g. errno. Also, see YDB_IS_YDBERR().

YDB_MIN_YDBERR

The absolute (positive) value of any YottaDB function error return code. If the absolute value of an error return code is less than YDB_MIN_YDBERR, then it is an error code from elsewhere, e.g. errno. Also, see YDB_IS_YDBERR().

Severity

Symbolic constants for the severities of message numbers in return codes and $zstatus are prefixed with YDB_SEVERITY_.

YDB_SEVERITY_ERROR

The number corresponds to an error from which the process can recover.

YDB_SEVERITY_FATAL

The number corresponds to an error that terminated the process.

YDB_SEVERITY_INFORMATIONAL

The number corresponds to an informational message.

YDB_SEVERITY_SUCCESS

The number corresponds to the successful completion of a requested operation.

YDB_SEVERITY_WARNING

The number corresponds to a warning, i.e., it indicates a possible problem.

Other

Other symbolic constants have a prefix of YDB_.

YDB_DEL_NODE and YDB_DEL_TREE

As values of the deltype parameter, these values indicate to ydb_delete_s() / ydb_delete_st() whether to delete an entire subtree or just the node at the root, leaving the subtree intact.

YDB_NOTTP

As a value of the tptoken parameter of the Simple API multi-threaded functions – those ending in _st(), indicates that the caller is not within a transaction.

Data Structures & Type Definitions

ydb_buffer_t

ydb_buffer_t is a descriptor for a string [1] value, and consists of the following fields:

  • buf_addr — pointer to an unsigned char, the starting address of a string.

  • len_alloc and len_used — fields of type unsigned int where:

    • len_alloc is the number of bytes allocated to store the string,

    • len_used is the length in bytes of the currently stored string, and

    • len_alloclen_used except when a YDB_ERR_INVSTRLEN occurs.

ydb_string_t

ydb_string_t is a descriptor for a string provided for compatibility with existing code, and consists of the following fields:

  • address — pointer to an unsigned char, the starting address of a string.

  • length — the length of the string starting at the address field.

ydb_tpfnptr_t

ydb_tpfnptr_t is a pointer to a function which returns an integer, with one parameter, a pointer to an arbitrary structure:

typedef int (*ydb_tpfnptr_t)(void *tpfnparm);

ydb_tp2fnptr_t

ydb_tp2fnptr_t is a pointer to a function which returns an integer, with three parameters, a tptoken, a *errstr pointer, and a pointer to an arbitrary structure:

typedef int (*ydb_tp2fnptr_t)(uint64_t tptoken, ydb_buffer_t *errstr, void *tpfnparm)

Functions to implement transaction processing logic for single-threaded applications are referenced by ydb_tpfnptr_t and functions to implement transaction processing logic for multi-threaded applications are referenced by ydb_tp2fnptr_t.

Macros

YDB_ASSERT(x)

Conditionally include this macro in code for debugging and testing purposes. If x is non-zero, it prints an error message on stderr and generates a core file by calling ydb_fork_n_core().

YDB_BUFFER_IS_SAME(buffer1, buffer2)

Use this macro to test whether the memory locations (strings) pointed to by two ydb_buffer_t structures have the same content, returning FALSE (0) if they differ and a non-zero value if the contents are identical.

YDB_COPY_BUFFER_TO_BUFFER(source, destination, done)

Use this macro to copy the memory locations (strings) pointed to by source to the memory locations pointed to by destination and set:

  • destination->len_used to source->len_used; and

  • done to TRUE if destination->len_allocsource->len_used and the underlying memcpy() completed successfully, and FALSE otherwise.

YDB_COPY_LITERAL_TO_BUFFER(literal, buffer, done)

Use this macro to copy a literal string to previously allocated memory referenced by a ydb_buffer_t structure (for example, to set an initial subscript to sequence through nodes). It sets:

  • buffer->len_used to the size of the literal; and

  • done to TRUE if buffer->len_alloc ≥ the size of the literal excluding its terminating null byte and the underlying memcpy() completed successfully, and FALSE otherwise.

YDB_COPY_STRING_TO_BUFFER(string, buffer, done)

Use this macro to copy a null-terminated string to previously allocated memory referenced by a ydb_buffer_t structure. This macro requires the code to also #include <string.h>. It sets:

  • buffer->len_used to the size of the copied string; and

  • done to TRUE if buffer->len_alloc ≥ the size of the string to be copied and the underlying memcpy() completed successfully, and FALSE otherwise.

YDB_FREE_BUFFER(BUFFERP)

Use this macro to free the buffer malloced using YDB_MALLOC_BUFFER.

  • free() call is used on BUFFERP->buf_addr.

YDB_LITERAL_TO_BUFFER(literal, buffer)

Use this macro to set a ydb_buffer_t structure to refer to a literal (such as a variable name). With a string literal, and a pointer to a ydb_buffer_t structure, set:

  • buffer->buf_addr to the address of literal; and

  • buffer->len_used and buffer->len_alloc to the length of literal excluding the terminating null byte.

YDB_IS_YDBERR(msgnum)

Returns TRUE if the absolute value of msgnum lies between YDB_MIN_YDBERR and YDB_MAX_YDBERR.

YDB_MALLOC_BUFFER(BUFFERP,LEN)

Use this macro to to allocate a buffer using malloc() of length LEN and assign it to an already allocated ydb_buffer_t structure.

  • BUFFERP->buf_addr is set to the malloced buffer.

  • BUFFERP->len_alloc is set to the malloced length.

  • BUFFERP->len_used is set to 0.

YDB_SEVERITY(msgnum, severity)

The error return code from a function indicates both the nature of an error as well as its severity. For message msgnum, the variable severity is set to one of the YDB_SEVERITY_* symbolic constants. YDB_SEVERITY() is only meaningful for error return codes and not other numbers. Use YDB_IS_YDBERR() to determine whether a return code is a YottaDB error return code.

HASH128_STATE_INIT(hash128_state_t *state, ydb_uint8 addl_seed)

Use this macro to initialize a variable in order to compute a 128-bit MurMurHash using ydb_mmrhash_128_ingest() / ydb_mmrhash_128_result().

Example:

// Initialize state struct
HASH128_STATE_INIT(hash_state, 0);

YDB_STRING_TO_BUFFER

Sets a ydb_buffer_t structure to point to an existing null-terminated C string, i.e.,

#define YDB_STRING_TO_BUFFER(STRING, BUFFERP)                           \
{                                                                       \
        (BUFFERP)->buf_addr = STRING;                                   \
        (BUFFERP)->len_used = (BUFFERP)->len_alloc = strlen(STRING);    \
}

YottaDB functions are divided into:

  • Simple API — a core set of functions that provides easy-to-use access to the major features of YottaDB.

  • Comprehensive API — a more elaborate set of functions for specialized or optimized access to additional functionality within libyottadb.so that YottaDB itself uses. The Comprehensive API is a project for the future.

  • Utility Functions — Functions useful to a C application using YottaDB.

Simple API

As all subscripts and node data passed to YottaDB using the Simple API are strings, use the sprintf() and atoi()/strtoul() family of functions to convert between numeric values and strings which are Canonical Numbers.

Note that all parameters passed to Simple API functions must be properly allocated and initialized where needed prior to the function call, including return values. This also specifically includes all members of ydb_buffer_t structs for parameters containing input values, but only buf_addr and len_alloc members for return values. To facilitate initialization of the ydb_buffer_t members, you may find the YDB_MALLOC_BUFFER macro helpful for heap allocations.

To allow the YottaDB Simple API functions to handle a variable tree whose nodes have varying numbers of subscripts, the actual number of subscripts is itself passed as a parameter. In the prototypes of functions, parameters of the form:

  • ydb_buffer_t *varname refers to the name of a variable;

  • int subs_used and int *subs_used refer to an actual number of subscripts; and

  • ydb_buffer_t *subsarray refers to an array of ydb_buffer_t structures used to pass subscripts whose actual number is defined by subs_used or *subs_used parameters.

To pass an intrinsic special variable, or unsubscripted local or global variable, subs_used should be zero and *subsarray should be NULL.

Caveat: Specifying a subs_used that exceeds the actual number of parameters passed in *subsarray will almost certainly result in an unpleasant bug that is difficult to troubleshoot.

Functions specific to the YottaDB Simple API for single-threaded applications end in _s() and those for multi-threaded applications end in _st(), with the latter functions typically differing from their counterparts of the former type with two additional parameters, tptoken, and errstr. The discussion in Threads provides more detailed information.

ydb_data_s() / ydb_data_st()

int ydb_data_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        unsigned int *ret_value);

int ydb_data_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        unsigned int *ret_value);

In the location pointed to by ret_value, ydb_data_s() and ydb_data_st() return the following information about the local or global variable node identified by *varname, subs_used and *subsarray.

  • 0 — There is neither a value nor a subtree, i.e., it is undefined.

  • 1 — There is a value, but no subtree

  • 10 — There is no value, but there is a subtree.

  • 11 — There are both a value and a subtree.

It is an error to call ydb_data_s() or ydb_data_st() on an intrinsic special variable; doing so results in the YDB_ERR_UNIMPLOP error. ydb_data_s() / ydb_data_st() returns:

The error YDB_ERR_PARAMINVALID is returned when

  • ret_value is NULL

  • len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript, in subsarray.

Please see the Simple API introduction for details about parameter allocation.

ydb_delete_s() / ydb_delete_st()

int ydb_delete_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        int deltype);

int ydb_delete_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        int deltype);

Delete nodes in the local or global variable tree or subtree specified. A value of YDB_DEL_NODE or YDB_DEL_TREE for deltype specifies whether to delete just the node at the root, leaving the (sub)tree intact, or to delete the node as well as the (sub)tree.

Intrinsic special variables cannot be deleted.

ydb_delete_s() and ydb_delete_st() return YDB_OK, a YDB_ERR_UNIMPLOP if deltype is neither YDB_DEL_NODE nor YDB_DEL_TREE, YDB_ERR_PARAMINVALID is returned when len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray, or another error return code.

  • YDB_OK;

  • YDB_ERR_UNIMPLOP if deltype is neither YDB_DEL_NODE nor YDB_DEL_TREE; or

  • another error return code.

Please see the Simple API introduction for details about parameter allocation.

ydb_delete_excl_s() / ydb_delete_excl_st()

int ydb_delete_excl_s(int namecount,
        ydb_buffer_t *varnames);

int ydb_delete_excl_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        int namecount, ydb_buffer_t *varnames);

ydb_delete_excl_s() and ydb_delete_excl_st() delete the trees of all local variables except those in the *varnames array. It is an error for *varnames to include a global or intrinsic special variable.

In the special case where namecount is zero, ydb_delete_excl_s() and ydb_delete_excl_st() delete all local variables. In this case, the varnames parameter is ignored so any value can be passed in for that parameter but we recommend that applications pass a NULL value.

If your application mixes M and non M code, and you wish to use ydb_delete_excl_s() to delete local variables that are aliases, formal parameters, or actual parameters passed by reference, make sure you understand what (sub)trees are being deleted. This warning does not apply to applications that do not include M code.

ydb_delete_excl_s() and ydb_delete_excl_st() return YDB_OK, YDB_ERR_NAMECOUNT2HI if more than YDB_MAX_NAMES are specified, or another error return code. YDB_ERR_PARAMINVALID is returned when len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one variable name in varnames.

Note that specifying a larger value for namecount than the number of variable names actually provided in *varnames can result in a buffer overflow.

Please see the Simple API introduction for details about parameter allocation.

ydb_get_s() / ydb_get_st()

int ydb_get_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *ret_value);

int ydb_get_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *ret_value);

To the user-allocated location pointed to by ret_value->buf_addr, ydb_get_s() and ydb_get_st() copy the value of the specified node or intrinsic special variable, setting ret_value->len_used on both normal and error returns (the latter case as long as the data exists). Return values are:

  • YDB_OK for a normal return;

  • YDB_ERR_GVUNDEF, YDB_ERR_INVSVN, or YDB_ERR_LVUNDEF as appropriate if no such variable or node exists;

  • YDB_ERR_INVSTRLEN if ret_value->len_alloc is insufficient for the value at the node;

  • YDB_ERR_PARAMINVALID when ret_value is NULL or ret_value->buf_addr is NULL and the return value has a non-zero len_used; or len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray; or

  • another applicable error return code.

Notes:

  • In the unlikely event an application wishes to know the length of the value at a node, but not access the data, it can call ydb_get_s() or ydb_get_st() and provide an output buffer (retvalue->len_alloc) with a length of zero, since even in the case of a YDB_ERR_INVSTRLEN error, retvalue->len_used is set.

  • Within a transaction implemented by ydb_tp_s() / ydb_tp_st() application code observes stable data at global variable nodes because YottaDB Transaction Processing ensures ACID properties, restarting the transaction if a value changes.

  • Outside a transaction, a global variable node can potentially be changed by another, concurrent, process between the time that a process calls ydb_data_s() / ydb_data_st() to ascertain the existence of the data and a subsequent call to ydb_get_s() / ydb_get_st() to get that data. A caller of ydb_get_s() / ydb_get_st() to access a global variable node should code in anticipation of a potential YDB_ERR_GVUNDEF, unless it is known from application design that this cannot happen.

Please see the Simple API introduction for details about parameter allocation.

ydb_incr_s() / ydb_incr_st()

int ydb_incr_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *increment,
        ydb_buffer_t *ret_value);

int ydb_incr_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *increment,
        ydb_buffer_t *ret_value);

ydb_incr_s() and ydb_incr_st() atomically:

  • convert the value in the specified node to a number if it is not one already, using a zero value if the node does not exist;

  • increment it by the value specified by *increment, converting the value to a number if it is not a canonical number, defaulting to 1 if the parameter is NULL; and

  • store the value as a canonical number in *ret_value.

Return values:

  • The normal return value is YDB_OK.

  • If the atomic increment results in a numeric overflow, the function returns a YDB_ERR_NUMOFLOW error; in this case, the value in the node is untouched and that in *ret_value is unreliable.

  • YDB_ERR_INVSTRLEN if ret_value->len_alloc is insufficient for the result. As with ydb_get_s() / ydb_get_st(), in this case ret_value->len_used is set to the required length.

  • Other errors return the corresponding error return code.

Notes:

  • Intrinsic special variables cannot be atomically incremented, and an attempt to do so returns the YDB_ERR_UNIMPLOP error.

  • The value of the empty string coerced to a numeric value is 0.

Please see the Simple API introduction for details about parameter allocation.

ydb_lock_s() / ydb_lock_st()

int ydb_lock_s(unsigned long long timeout_nsec,
        int namecount[,
        [ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray], ...]);

int ydb_lock_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        unsigned long long timeout_nsec,
        int namecount[,
        [ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray], ...]);

namecount is the number of variable names in the call.

Release any locks held by the process, and attempt to acquire all the requested locks. Except in the case of an error, the release is unconditional. On return, the function will have acquired all requested locks or none of them. If no locks are requested (namecount is zero), the function releases all locks and returns YDB_OK.

timeout_nsec specifies a time in nanoseconds that the function waits to acquire the requested locks. If timeout_nsec is zero, the function makes exactly one attempt to acquire the locks

Return values:

  • If all requested locks are successfully acquired, the function returns YDB_OK.

  • If it is not able to acquire all requested locks in the specified time, it acquires no locks, returning with a YDB_LOCK_TIMEOUT return value.

  • If the requested timeout_nsec exceeds YDB_MAX_TIME_NSEC, the function immediately returns YDB_ERR_TIME2LONG.

  • YDB_ERR_PARAMINVALID is returned when len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray.

  • In other cases, the function returns an error return code.

Please see the Simple API introduction for details about parameter allocation.

ydb_lock_decr_s() / ydb_lock_decr_st()

int ydb_lock_decr_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray);

int ydb_lock_decr_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray);

Decrements the count of the specified lock held by the process. As noted in the Concepts section, a lock whose count goes from 1 to 0 is released. A lock whose name is specified, but which the process does not hold, is ignored.

As releasing a lock cannot fail, the function returns YDB_OK, unless there is an error such as an invalid name that results in the return of an error code such as YDB_ERR_INVVARNAME. Errors result in an appropriate error return code. YDB_ERR_PARAMINVALID is returned when len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray.

Please see the Simple API introduction for details about parameter allocation.

ydb_lock_incr_s() / ydb_lock_incr_st()

int ydb_lock_incr_s(unsigned long long timeout_nsec,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray);

int ydb_lock_incr_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        unsigned long long timeout_nsec,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray);

Without releasing any locks held by the process attempt to acquire the requested lock, incrementing it if already held.

timeout_nsec specifies a time in nanoseconds that the function waits to acquire the requested locks. If timeout_nsec is zero, the function makes exactly one attempt to acquire the locks

Return values:

  • If all requested locks are successfully acquired, the function returns YDB_OK.

  • If it is not able to acquire all requested locks in the specified time, it acquires no locks, returning with a YDB_LOCK_TIMEOUT return value.

  • If the requested timeout_nsec exceeds YDB_MAX_TIME_NSEC, the function immediately returns YDB_ERR_TIME2LONG.

  • YDB_ERR_PARAMINVALID is returned when len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray.

  • In other cases, the function returns an error return code.

Please see the Simple API introduction for details about parameter allocation.

ydb_node_next_s() / ydb_node_next_st()

int ydb_node_next_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        int *ret_subs_used,
        ydb_buffer_t *ret_subsarray);

int ydb_node_next_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        int *ret_subs_used,
        ydb_buffer_t *ret_subsarray);

ydb_node_next_s() and ydb_node_next_st() facilitate traversal of a local or global variable tree. As the number of subscripts can differ between the input node of the call and the output node reported by the call *ret_subs_used is an input as well as an output parameter:

  • On input, *ret_subs_used specifies the number of elements allocated for returning the subscripts of the next node.

  • On normal output (YDB_OK return code), *ret_subs_used contains the actual number of subscripts returned. See below for error return codes

Return values of ydb_node_next_s() and ydb_node_next_st() are:

  • YDB_OK with the next node, if there is one, changing *ret_subs_used and *ret_subsarray parameters to those of the next node. If there is no next node (i.e., the input node is the last), *ret_subs_used on output is YDB_NODE_END.

  • YDB_ERR_INSUFFSUBS if *ret_subs_used specifies insufficient parameters to return the subscript. In this case *ret_subs_used reports the actual number of subscripts required.

  • YDB_ERR_INVSTRLEN if one of the ydb_buffer_t structures pointed to by *ret_subsarray does not have enough space for the subscript. In this case, *ret_subs_used is the index into the *ret_subsarray array with the error, and the len_used field of that structure specifies the size required.

  • YDB_ERR_NODEEND to indicate that that there are no more nodes. In this case, *ret_subs_used is unchanged.

  • YDB_ERR_PARAMINVALID if ret_subs_used is NULL or ret_subsarray is NULL or one of the ydb_buffer_t structures pointed to by *ret_subsarray has a NULL buf_addr. In the last case, *ret_subs_used is the index into the *ret_subsarray array with the NULL buf_addr.

  • Another error return code, in which case the application should consider the values of *ret_subs_used and the *ret_subsarray to be undefined.

Please see the Simple API introduction for details about parameter allocation.

ydb_node_previous_s() / ydb_node_previous_st()

int ydb_node_previous_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        int *ret_subs_used,
        ydb_buffer_t *ret_subsarray);

int ydb_node_previous_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        int *ret_subs_used,
        ydb_buffer_t *ret_subsarray);

Analogous to ydb_node_next_s() / ydb_node_next_st(), ydb_node_previous_s() and ydb_node_previous_st() facilitate reverse traversal of a local or global variable tree, except that ydb_node_previous_s() and ydb_node_previous_st() search for and report the predecessor node. Unlike ydb_node_next_s() / ydb_node_next_st(), *ret_subs_used can be zero if the previous node is the unsubscripted root.

Return values of ydb_node_previous_s() and ydb_node_previous_st() are:

  • YDB_OK with the previous node, if there is one, changing *ret_subs_used and *ret_subsarray parameters to those of the previous node.

  • YDB_ERR_INSUFFSUBS if *ret_subs_used specifies insufficient parameters to return the subscript. In this case *ret_subs_used reports the actual number of subscripts required.

  • YDB_ERR_INVSTRLEN if one of the ydb_buffer_t structures pointed to by *ret_subsarray does not have enough space for the subscript. In this case, *ret_subs_used is the index into the *ret_subsarray array with the error, and the len_used field of that structure specifies the size required.

  • YDB_ERR_NODEEND to indicate that that there are no more nodes. In this case, *ret_subs_used is unchanged.

  • YDB_ERR_PARAMINVALID if ret_subs_used is NULL or ret_subsarray is NULL or one of the ydb_buffer_t structures pointed to by *ret_subsarray has a NULL buf_addr. In the last case, *ret_subs_used is the index into the *ret_subsarray array with the NULL buf_addr.

  • Another error return code, in which case the application should consider the values of *ret_subs_used and the *ret_subsarray to be undefined.

Please see the Simple API introduction for details about parameter allocation.

ydb_set_s() / ydb_set_st()

int ydb_set_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *value);

int ydb_set_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *value);

ydb_set_s() and ydb_set_st() copy the value->len_used bytes at value->buf_addr as the value of the specified node or intrinsic special variable specified. A NULL value parameter is treated as equivalent to one that points to a ydb_buffer_t specifying an empty string. Return values are:

  • YDB_OK for a normal return;

  • YDB_ERR_INVSVN if no such intrinsic special variable exists;

  • YDB_ERR_PARAMINVALID when len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray or increment; or

  • another applicable error return code.

Please see the Simple API introduction for details about parameter allocation.

ydb_str2zwr_s() / ydb_str2zwr_st()

int ydb_str2zwr_s(ydb_buffer_t *str, ydb_buffer_t *zwr);

int ydb_str2zwr_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *str, ydb_buffer_t *zwr);

In the buffer referenced by *zwr, ydb_str2zwr_s() and ydb_str2zwr_st() provide the zwrite formatted version of the string pointed to by *str, returning:

  • YDB_OK;

  • YDB_ERR_INVSTRLEN if the *zwr buffer is not long enough;

  • YDB_ERR_PARAMINVALID if zwr is NULL or zwr->buf_addr is NULL and the return value has a non-zero len_used; or

  • another applicable error return code.

Please see the Simple API introduction for details about parameter allocation.

ydb_subscript_next_s() / ydb_subscript_next_st()

int ydb_subscript_next_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *ret_value);

int ydb_subscript_next_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *ret_value);

ydb_subscript_next_s() and ydb_subscript_next_st() provide a primitive for implementing traversal of a tree by searching for the next subscript at the level specified by subs_used, i.e., the next subscript after the one referred to by subsarray[subs_used-1].buf_addr. A node need not exist at the subscripted variable name provided as input to the function. If subsarray[subs_used-1].len_used is zero, ret_value->buf_addr points to first node at that level with a subscript that is not the empty string. ydb_subscript_next_s() and ydb_subscript_next_st() return:

  • YDB_OK, in which case ret_value->buf_addr points to the value of that next subscript;

  • YDB_ERR_NODEEND when there are no more subscripts at that level, in which case *ret_value is unchanged;

  • YDB_ERR_PARAMINVALID when

    • ret_value is NULL;

    • ret_value->buf_addr is NULL and the return value has a non-zero len_used; or

    • len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray

  • or another error return code.

In the special case where subs_used is zero, and the function returns YDB_OK, ret_value->buf_addr points to the next local or global variable name, with YDB_ERR_NODEEND indicating an end to the traversal.

Please see the Simple API introduction for details about parameter allocation.

ydb_subscript_previous_s() / ydb_subscript_previous_st()

int ydb_subscript_previous_s(ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *ret_value);

int ydb_subscript_previous_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *varname,
        int subs_used,
        ydb_buffer_t *subsarray,
        ydb_buffer_t *ret_value);

ydb_subscript_previous_s() and ydb_subscript_previous_st() provide a primitive for implementing reverse traversal of a tree by searching for the previous subscript at the level specified by subs_used. i.e. the subscript preceding the one referred to by subsarray[subs_used-1].buf_addr. A node need not exist at the subscripted variable name provided as input to the function. If subsarray[subs_used-1].len_used is zero, ret_value->buf_addr points to last node at that level with a subscript that is not the empty string. ydb_subscript_previous_s() and ydb_subscript_previous_st() return:

  • YDB_OK, in which case ret_value->buf_addr points to the value of that previous subscript;

  • YDB_ERR_NODEEND when there are no more subscripts at that level, in which case *ret_value is unchanged;

  • YDB_ERR_PARAMINVALID when

    • ret_value is NULL;

    • ret_value->buf_addr is NULL and the return value has a non-zero len_used; or

    • len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one subscript in subsarray

  • or another error return code.

In the special case where subs_used is zero, and the function returns YDB_OK, ret_value->buf_addr points to the previous local or global variable name, with YDB_ERR_NODEEND indicating an end to the traversal.

Please see the Simple API introduction for details about parameter allocation.

ydb_tp_s() / ydb_tp_st()

int ydb_tp_s(ydb_tpfnptr_t tpfn,
        void *tpfnparm,
        const char *transid,
        int namecount,
        ydb_buffer_t *varnames);

int ydb_tp_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_tp2fnptr_t tpfn,
        void *tpfnparm,
        const char *transid,
        int namecount,
        ydb_buffer_t *varnames);

ydb_tp_s() and ydp_tp_st() call the function referenced by tpfn passing it tpfnparm as a parameter. Additionally, ydb_tp_st() also generates a new tptoken that it passes as a parameter to the function referenced by its tpfn parameter.

As discussed under Transaction Processing, a function implementing transaction processing logic should use the intrinsic special variable $trestart to manage any externally visible action (which YottaDB recommends against, but which may be unavoidable). The function referenced by tpfn should return one of the following:

  • YDB_OK — application logic indicates that the transaction can be committed (the YottaDB engine may still decide that a restart is required to ensure ACID transaction properties) as discussed under Transaction Processing.

  • YDB_TP_RESTART — application logic indicates that the transaction should restart.

  • YDB_TP_ROLLBACK — application logic indicates that the transaction should not be committed.

  • YDB_ERR_PARAMINVALID when len_alloc < len_used or the len_used is non-zero and buf_addr is NULL in at least one variable name in varnames.

  • An error return code returned by a YottaDB function called by the function. This case is treated the same way as if YDB_TP_ROLLBACK was returned (i.e. the application indicates that this transaction should not be committed).

transid is a string, up to the first 8 bytes of which are recorded in the commit record of journal files for database regions participating in the transaction. If not NULL or the empty string, a case-insensitive value of "BA" or "BATCH" indicates that at transaction commit, YottaDB need not ensure Durability (it always ensures Atomicity, Consistency, and Isolation). Use of this value may improve latency and throughput for those applications where an alternative mechanism (such as a checkpoint) provides acceptable Durability. If a transaction that is not flagged as "BATCH" follows one or more transactions so flagged, Durability of the later transaction ensures Durability of the the earlier "BATCH" transaction(s).

If namecount>0, varnames[i] where 0≤i<namecount specifies local variable names whose values are restored to their original values when the transaction is restarted. In the special case where namecount=1 and varnames[0] provides the value "*", all local variables are restored on a restart. It is an error for a varnames to include a global or intrinsic special variable.

A top level ydb_tp_s() and ydb_tp_st() can return:

A ydb_tp_s() or ydb_tp_st() call that is within another transaction (i.e., a nested transaction) can also return YDB_TP_RESTART to its caller. [2]

Note

If the transaction logic receives a YDB_TP_RESTART from a YottaDB function that it calls, it must return that value to the calling ydb_tp_s() or ydb_tp_st(). Failure to do so could result in application level data inconsistencies and hard to debug application code.

Please see the Simple API introduction for details about parameter allocation.

ydb_zwr2str_s() / ydb_zwr2str_st()

int ydb_zwr2str_s(ydb_buffer_t *zwr, ydb_buffer_t *str);

int ydb_zwr2str_st(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_buffer_t *zwr, ydb_buffer_t *str);

In the buffer referenced by *str, ydb_zwr2str_s() and ydb_zwr2str_st() provide the string described by the zwrite formatted string pointed to by *zwr, returning

  • YDB_OK (with str->len_used set to zero if the zwrite formatted string has an error);

  • YDB_ERR_INVSTRLEN error if the *str buffer is not long enough;

  • YDB_ERR_PARAMINVALID either if the *str buffer is NULL or the return value contains a non-zero len_used and the str->buf_addr is NULL.

Please see the Simple API introduction for details about parameter allocation.

Comprehensive API

The Comprehensive API is a project for the future.

YottaDB C to M APIs

YottaDB C code has the ability to call M code. This allows you to reuse existing M mcode written previously, as well as write code in M that may be easier to write than writing the same code in C, then call it from C from your application.

The C API needs a small text file called a "call-in table" that maps typed C parameters to the typeless M code. This call-in table can be set as an environment variable ydb_ci, or it can be set from the C code at runtime.

Here's a listing of these APIs. The APIs ending with _t are for use from threaded applications. The discussion in Threads provides more detailed information. See the Programmers Guide Call-In Interface for full description as well as a compilable example.

API

Description

ydb_ci/ ydb_ci_t

The most common API to use. Call an M function by its name in a call-in table.

ydb_cip/ ydb_cip_t

ydb_ci* looks up the function each time it is called. While this takes a very small amount of time, it can prove costly with thousands or millions of invocations. This version allows you to cache the name lookup; but it's harder to use.

ydb_ci_tab_open/ ydb_ci_tab_open_t

This opens a call-in table in a specific file.

ydb_ci_tab_switch/ ydb_ci_tab_switch_t

This switches to a call-in table just opened above. You can have multiple call-in tables open at the same time and switch between them.

Utility Functions

Utility functions are functions that are not core to YottaDB functionality, but which are useful to application code.

Utility functions whose names end in _t() are for use by multi-threaded applications, and those which do not are for single-threaded applications. The discussion in Threads provides more detailed information.

ydb_hiber_start() and ydb_hiber_start_wait_any() are for use only with the SimpleAPI and not with the threaded Simple API.

ydb_exit(), ydb_fork_n_core(), and ydb_init() do not have separate variants for single- and multi-threaded applications and are suitable for both.

ydb_call_variadic_plist_func()

int ydb_call_variadic_plist_func(ydb_vplist_func cgfunc, gparam_list *cvplist)

ydb_call_variadic_plist_func allows a language wrapper to make pseudo variadic calls to routines if the wrapper doesn't support variadic calls. Since some variadic calls are required to interface properly with YottaDB interfaces (e.g., ydb_ci(), ydb_cip, and ydb_lock_st() etc.) this routine is needed. The return value is the same as the return value from the function. For example, if ydb_call_variadic_plist_func() is used to call ydb_cip() then a 0 return value indicates successful completion.

The ydb_vplist_func type is defined as follows:

typedef uintptr_t (*ydb_vplist_func)();

The gparam_list type is defined as follows:

typedef struct gparam_list_struct
{
     intptr_t        n;                              /* Count of parameter/arguments */
     void            *arg[MAX_GPARAM_LIST_ARGS];     /* Parameter/argument array */
} gparam_list;

The first field n is the count of valid parameters, which can have a maximum value of MAX_GPARAM_LIST_ARGS (currently 36).

To use ydb_call_variadic_plist_func(), the cvplist array needs to be filled in. Each element in the array is sized to hold a pointer. The arg array holds all of the parameters (a maximum of 36 entries at this time) to be passed to the function. If a parameter does not fit as a single element, multiple elements can be used but this must be done in accordance with the calling API of the particular system.

Note

On a 32 bit machine, each argument is only 32 bits wide. To pass a 64 bit value like a ydb_double_t in a portable way, you should instead pass a pointer to it using ydb_double_t *. For this reason, ydb_double_t and ydb_int64_t have been disabled on 32 bit machines, but you can still use ydb_double_t* and ydb_int64_t*

Note

Third-party language wrappers that use ydb_call_variadic_plist_func() to implement call-ins need to respect the limitations of the calling convention (ABI), as not all types can be passed via ydb_call_variadic_plist_func(). For example, some ABIs pass floating point types in FPU registers rather than in a memory array, or cannot pass 64-bit types in one parameter slot, so these types cannot be passed to ydb_call_variadic_plist_func(). It is always safe to pass and return these types as pointer types like ydb_double_t* and ydb_int64_t*. If desired, the language wrapper can automatically translate the user's call-in table from ydb_float_t and ydb_int64_t types to ydb_float_t* and ydb_int64_t* types, as the called M code will be the same.

ydb_child_init()

YottaDB r1.22 and before required the use of a function ydb_child_init() immediately after a fork() to avoid database damage and other possible side-effects.

Effective YottaDB r1.24, this function is not needed. It gets automatically invoked by YottaDB as needed. Any existing usages of this function in an application can be safely removed assuming YottaDB r1.24 or later is in use.

ydb_eintr_handler() / ydb_eintr_handler_t()

int ydb_eintr_handler(void)

int ydb_eintr_handler_t(uint64_t tptoken, ydb_buffer_t *errstr)

ydb_eintr_handler() needs to be invoked by a SimpleAPI application whenever a system call that it invokes (e.g. accept(), select()) returns an error with errno set to EINTR (this usually means a signal interrupted the system call). This ensures that YottaDB takes appropriate action corresponding to the interrupting signal in a timely fashion. For example, if the signal SIGTERM was sent externally to this SimpleAPI application process, the appropriate action is to terminate the process as soon as a safe/logical point is reached.

Note that not invoking ydb_eintr_handler() as part of an EINTR situation can cause the SimpleAPI application to behave unexpectedly. For example, in the SIGTERM case, the process would not terminate how ever many signals are sent.

ydb_eintr_handler_t() is very similar to ydb_eintr_handler() except that it needs to be invoked by a SimpleThreadAPI application.

ydb_exit()

int ydb_exit(void)

When a caller no longer wishes to use YottaDB, a call to ydb_exit() cleans up the process connection/access to all databases and cleans up its data structures. Therafter, any attempt to call a YottaDB function produces a YDB_ERR_CALLINAFTERXIT error.

Note that:

  • a typical application should not need to call ydb_exit(), but should instead just terminate with a call to exit() which will perform any cleanup needed by YottaDB; and

  • calling ydb_exit() before calling any other YottaDB function does nothing, i.e., it is a no-op.

ydb_exit() returns YDB_OK on success, and a positive non-zero value on error. If ydb_exit() has already been called, later calls to ydb_exit() in the same process return YDB_OK with no further action, since all resources related to YottaDB are already cleaned up by the first call.

If an external call attempts to call ydb_exit(), a YDB_ERR_INVYDBEXIT error is returned, since YottaDB is required to remain operational even after the external call returns. For information about this error, see INVYDBEXIT in the Messages and Recovery Procedures guide.

ydb_exit() can be used with both the Simple API and threaded Simple API.

ydb_file_id_free() / ydb_file_id_free_t()

int ydb_file_id_free(ydb_fileid_ptr_t fileid)

int ydb_file_id_free_t(uint64_t tptoken,
        ydb_buffer_t *errstr, ydb_fileid_ptr_t fileid)

Releases the memory used by a fileid structure previously generated by ydb_file_name_to_id() / ydb_file_name_to_id_t(). Calling the function twice for the same pointer, unless it has been returned a second time by a different ydb_file_name_to_id() / ydb_file_name_to_id_t() is an application error with undefined consequences.

A PARAMINVALID error is issued if the input fileid parameter is NULL.

Please see the Simple API introduction for details about parameter allocation.

ydb_file_is_identical() / ydb_file_is_identical_t()

int ydb_file_is_identical(ydb_fileid_ptr_t fileid1,
        ydb_fileid_ptr_t fileid2)

int ydb_file_is_identical_t(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_fileid_ptr_t fileid1,
        ydb_fileid_ptr_t fileid2)

Given two pointers to fileid structures (see ydb_file_name_to_id() / ydb_file_name_to_id_t()), ydb_file_is_identical() and ydb_file_is_identical_t() return YDB_OK if the two fileid structures are the same file and YDB_NOTOK otherwise.

A PARAMINVALID error is issued if the input fileid parameter is NULL.

Please see the Simple API introduction for details about parameter allocation.

ydb_file_name_to_id() / ydb_file_name_to_id_t()

int ydb_file_name_to_id(ydb_string_t *filename,
        ydb_fileid_ptr_t *fileid)

int ydb_file_name_to_id_t(uint64_t tptoken,
        ydb_buffer_t *errstr,
        ydb_string_t *filename,
        ydb_fileid_ptr_t *fileid)

As a file is potentially reachable through different paths, and application code may need to check whether two paths do indeed lead to the same file, YottaDB provides a mechanism to do so. Provided with a path to a file, YottaDB creates an internal structure called a fileid that uniquely identifies the file if such a structure does not already exist for that file, and provides the caller with a pointer to that structure. The layout and contents of the fileid structure are opaque to the caller, which must not modify the pointer or the structure it points to.

When the fileid structure for a file is no longer needed, an application should call ydb_file_id_free() / ydb_file_id_free_t() to release the structure and avoid a memory leak.

ydb_file_name_to_id() and ydb_file_name_to_id_t() return YDB_OK, or an error return code.

A PARAMINVALID error is issued if the input filename or fileid parameter is NULL.

Please see the Simple API introduction for details about parameter allocation.

ydb_fork_n_core()

void ydb_fork_n_core(void)

A core is a snapshot of a process, to help debug application code, for example to troubleshoot an out-of-design condition. When a process executes ydb_fork_n_core(), it forks. The child process sends itself a signal to generate a core and terminate. On termination of the child process, the parent process continues execution. Note that depending on the nature of the condition necessitating a core, an exit() may well be the right action for the parent process. An exit() call will drive YottaDB exit handlers to perform clean shutdown of databases and devices the process has open.

The content, location, and naming of cores is managed by the operating system – see man 5 core for details. We recommend that you set kernel.core_uses_pid to 1 to make it easier to identify and track cores. As cores will likely contain protected confidential information, you must ensure appropriate configuration and management of cores.

In a multi-threaded environment, only the thread that executes ydb_fork_n_core() or ydb_fork_n_core() survives in the child and is dumped.

ydb_fork_n_core() can be used with both the Simple API and threaded Simple API.

ydb_free()

void ydb_free(void *ptr)

Releases memory previously allocated by ydb_malloc(). Passing ydb_free() a pointer not previously provided to the application by ydb_malloc() can result in unpredictable behavior. The signature of ydb_free() matches that of the POSIX free() call.

ydb_free() should not be used in multiple threads in multi-threaded programs. (See the Threads section for details). However, the YDB_FREE_BUFFER macro is safe to use in multiple threads.

ydb_hiber_start()

int ydb_hiber_start(unsigned long long sleep_nsec)

The process or thread sleeps for the time in nanoseconds specified by sleep_nsec. If a value greater than YDB_MAX_TIME_NSEC is specified, ydb_hiber_start() immediately returns with a YDB_ERR_TIME2LONG error; otherwise they return YDB_OK after the elapsed time.

ydb_hiber_start() should not be used in multiple threads in multi-threaded programs. (See the Threads section for details).

ydb_hiber_start_wait_any()

int ydb_hiber_start_wait_any(unsigned long long sleep_nsec)

The process or thread sleeps for the time in nanoseconds specified by sleep_nsec or until it receives a signal. If a value greater than YDB_MAX_TIME_NSEC is specified, ydb_hiber_start_wait_any() immediately returns with a YDB_ERR_TIME2LONG error; otherwise they return YDB_OK after the elapsed time or when the wait is terminated by a signal.

ydb_hiber_start_wait_any() should not be used in multiple threads in multi-threaded programs. (See the Threads section for details).

ydb_init()

int ydb_init(void)

ydb_init() initializes the YottaDB runtime environment. As YottaDB automatically initializes the runtime on the first call to its API or first M code invocation, there is usually no need to explicitly call ydb_init(). The exception is when an application wishes to set its own signal handlers (see Signals): ydb_init() sets signal handlers, and in case an application wishes to set its own signal handlers for signals not used by YottaDB, it can call ydb_init() before setting its signal handlers.

ydb_init() returns YDB_OK on success, and a positive non-zero value otherwise. On failure, the error message text corresponding to the non-zero return value can be obtained by immediately calling ydb_zstatus().

If ydb_init() has already been called, later calls to ydb_init() in the same process return YDB_OK with no further action, since the YottaDB runtime has already been initialized.

ydb_init() can be used with both the Simple API and threaded Simple API.

ydb_malloc()

void *ydb_malloc(size_t size)

With a signature matching that of the POSIX malloc() call, ydb_malloc() returns an address to a block of memory of the requested size, or NULL if it is unable to satisfy the request. ydb_malloc() uses a buddy system, and provides debugging functionality under the control of the environment variable ydb_dbglvl whose values are a mask as described in gtmdbglvl.h.

ydb_malloc() should not be used in multiple threads in multi-threaded programs. (See the Threads section for details). However, the YDB_MALLOC_BUFFER macro is safe to use in multiple threads.

ydb_message() / ydb_message_t()

int ydb_message(int errnum, ydb_buffer_t *msg_buff)

int ydb_message_t(uint64_t tptoken, ydb_buffer_t *errstr,
        int errnum, ydb_buffer_t *msg_buff)

The functions return the error message text template for the error number specified by errnum.

  • If errnum does not correspond to an error that YottaDB recognizes, the return the error YDB_ERR_UNKNOWNSYSERR, leaving the structures referenced by msg_buff unaltered.

  • Otherwise, if the length of the text exceeds msg_buff->len_alloc they return the error YDB_ERR_INVSTRLEN. In this case msg_buff->len_used is greater than msg_buff->len_alloc.

  • Otherwise, if msg_buff->buf_addr is NULL, they return the error YDB_ERR_PARAMINVALID.

  • Otherwise, the copy the text to the buffer specified by msg_buff->buf_addr, set msg_buff->len_used to its length, and return YDB_OK.

Please see the Simple API introduction for details about parameter allocation.

ydb_mmrhash_32()

void ydb_mmrhash_32(const void *key, int len, uint4 seed, uint4 *out4);

This function returns in *out4 the 32-bit (4-byte) MurmurHash of len bytes at *key.

Please see the Simple API introduction for details about parameter allocation.

ydb_mmrhash_128()

void ydb_mmrhash_128(const void *key, int len, uint4 seed, ydb_uint16 *out);

This function returns in *out the 128-bit (16-byte) MurmurHash of len bytes at *key.

Please see the Simple API introduction for details about parameter allocation.

ydb_mmrhash_128_ingest() / ydb_mmrhash_128_result()

void ydb_mmrhash_128_ingest(hash128_state_t *state, const void *key, int len);

void ydb_mmrhash_128_result(hash128_state_t *state, uint4 addl_seed, ydb_uint16 *out);

These functions enable users to get a MurmurHash through a series of incremental operations.

The sequence is to first initialize the "state" variable using the HASH128_STATE_INIT(hash128_state_t *state, ydb_uint8 addl_seed) macro, then call ydb_mmrhash_128_ingest() one or more times and finally call ydb_mmrhash_128_result() to obtain the final hash value. "key" points to the input character array (of length "len") for the hash. "addl_seed" can either be the last four bytes of the input, or at the application's discretion, an additional seed or salt. An example is to set it to the sum of the "len" values passed in across all calls to ydb_mmrhash_128_ingest before ydb_mmrhash_128_result is called. "out" points to the structure holding the 16-byte hash result.

Example:

// Initialize state struct
HASH128_STATE_INIT(hash_state, 0);

// Create keys/strings to ingest
char *key1 = "ifembu8r308j243h5g3h84t7yf23h0h";
char *key2 = "ougoh2408rh2fhe08yh2ti8rhhrguo2r3huocdiWEN23";

// Add keys to hash
ydb_mmrhash_128_ingest(&hash_state, (void*)key1, strlen(key1));
ydb_mmrhash_128_ingest(&hash_state, (void*)key2, strlen(key2));

// Produce result
ydb_mmrhash_128_result(hash_state, 0, &hash);

Please see the Simple API introduction for details about parameter allocation.

ydb_mmrhash_128_hex()

void ydb_mmrhash_128_hex(const ydb_uint16 *hash, unsigned char *out);

This function returns a hex formatted representation of a 16-byte hash value. As the function does no checking, if *out is not at least 32 bytes, a buffer overflow can occur, potentially with unpleasant consequences such as abnormal process termination with a SIG-11, or worse.

Example:

char out[16];
ydb_mmrhash_128_hex(&hash, out);

Please see the Simple API introduction for details about parameter allocation.

ydb_mmrhash_128_bytes()

void ydb_mmrhash_128_bytes(const ydb_uint16 *hash, unsigned char *out);

This function converts the 16-byte hash stored in a "ydb_uint16" structure (2 8-byte integers) into a byte array "out" of 16 characters. It is also internally used by ydb_mmrhash_128_hex().

Example:

char out[16];
ydb_mmrhash_128_bytes(&hash, out);

Please see the Simple API introduction for details about parameter allocation.

ydb_stdout_stderr_adjust() / ydb_stdout_stderr_adjust_t()

int ydb_stdout_stderr_adjust(void)

int ydb_stdout_stderr_adjust_t(uint64 tptoken,
        ydb_buffer_t *errstr)

The functions check whether stdout (file descriptor 1) and stderr (file descriptor 2) are the same file, and if so, route stderr writes to stdout instead. This ensures that output appears in the order in which it was written; otherwise owing to IO buffering, output can appear in an order different from that in which it was written. Application code which mixes C and M code, and which explicitly redirects stdout or stderr (e.g., using dup2()), should call one of these functions as soon as possible after the redirection. ydb_stdout_stderr_adjust() and ydb_stdout_stderr_adjust_t() return YDB_OK.

Please see the Simple API introduction for details about parameter allocation.

ydb_thread_is_main()

int ydb_thread_is_main(void)

The functions return YDB_OK if the thread is the main thread of the process, and another value if the thread is not. YottaDB recommends against application code that requires use of these functions, which exist only to provide backward compatibility to a specific application code base (see discussion under Threads).

ydb_timer_cancel() / ydb_timer_cancel_t()

void ydb_timer_cancel(intptr_t timer_id)

void ydb_timer_cancel_t(uint64_t tptoken,
        ydb_buffer_t *errstr, intptr_t timer_id)

Cancel a timer identified by timer_id and previously started with ydb_timer_start() / ydb_timer_start_t().

Please see the Simple API introduction for details about parameter allocation.

ydb_timer_start() / ydb_timer_start_t()

typedef void (*ydb_funcptr_retvoid_t)(intptr_t timer_id,
        unsigned int handler_data_len,
        char *handler_data);

int ydb_timer_start(intptr_t timer_id,
        unsigned long long limit_nsec,
        ydb_funcptr_retvoid_t handler,
        unsigned int handler_data_len,
        char *handler_data);

int ydb_timer_start_t(uint64_t tptoken,
        ydb_buffer_t *errstr,
        intptr_t timer_id,
        unsigned long long limit_nsec,
        ydb_funcptr_retvoid_t handler,
        unsigned int handler_data_len,
        char *handler_data);

Start a timer. Unless canceled, when the timer expires, ydb_timer_start() and ydb_timer_start_t() invoke a handler function, providing that function with input data.

timer_id is an identifier for the the timer. It is the responsibility of application code to ensure that timer_id is different from those of any other active / pending timers.

limit_nsec is the minimum number of nanoseconds before the timer expires and invokes the handler function. Owing to overhead and system load, the actual time will almost always be greater than this value.

handler is a pointer to the function to be called when the timer expires.

handler_data is a pointer to the data to be passed to handler and handler_data_len is the length of the data at *handler_data. Note that the data it points to must be on the heap rather than on the stack, as the stack frame may no longer be valid when the timer expires.

If the requested timeout_nsec exceeds YDB_MAX_TIME_NSEC, the functions return YDB_ERR_TIME2LONG; otherwise they return YDB_OK.

Please see the Simple API introduction for details about parameter allocation.

Calling M Routines

M routines can be called from C with the following functions which are described in the M Programmers Guide:

Historically, the predecessors of the functions to call M routines returned positive return codes. In order to maintain backward compatibility, values returned by the above are positive values, whereas YottaDB Error Return Codes are negative. For example, to return an invalid string length (YDB_ERR_INVSTRLEN), the ydb_ci*() functions return -YDB_ERR_INVSTRLEN, which is a positve value because YDB_ERR_STRLEN is a negative value.

Effective release r1.30. ydb_zstatus() returns an int.