Corto API Reference
  1. chevron_right  In-memory Store

    API for accessing and populating the in-memory store.

  2. subject  corto_create
  3. subject  corto_declare
  4. subject  corto_define
  5. subject  corto_delete
  6. subject  corto_update
  7. subject  corto_update_begin
  8. subject  corto_update_end
  9. subject  corto_update_cancel
  10. subject  corto_invalidate
  11. subject  corto_claim
  12. subject  corto_release
  13. subject  corto_typeof
  14. subject  corto_stateof
  15. subject  corto_attrof
  16. subject  corto_isorphan
  17. subject  corto_isbuiltin
  18. subject  corto_countof
  19. subject  corto_idof
  20. subject  corto_nameof
  21. subject  corto_parentof
  22. subject  corto_sourceof
  23. subject  corto_lookup
  24. subject  corto_resolve
  25. subject  corto_observe
  26. subject  corto_observe fluent methods
  27. subject  corto_unobserve
  28. subject  corto_serialize
  29. subject  corto_deserialize
  30. subject  corto_serialize_value
  31. subject  corto_deserialize_value
  32. subject  corto_fmt_lookup
  33. subject  corto_read_begin
  34. subject  corto_read_end
  35. subject  corto_lock
  36. subject  corto_unlock
  37. subject  corto_set_attr
  38. subject  corto_get_attr
  39. subject  corto_set_source
  40. subject  corto_get_source
  41. subject  corto_login
  42. subject  corto_logout
  43. subject  corto_set_session
  44. subject  corto_authorize
  45. subject  corto_authorize_id
  46. subject  corto_useradd
  47. subject  corto_userdel
  48. subject  corto_secured
  49. subject  corto_check_state
  50. subject  corto_check_attr
  51. subject  corto_copy
  52. subject  corto_compare
  53. subject  corto_instanceof
  54. subject  corto_type_instanceof
  55. subject  corto_fullpath
  56. subject  corto_path
  57. subject  corto_childof
  58. subject  corto_owned
  59. subject  corto_scope_size
  60. subject  corto_scope_claim
  61. subject  corto_scope_release
  62. subject  corto_scope_walk
  63. chevron_right  Virtual Store

    API for accessing and populating the virtual store.

  64. subject  corto_select
  65. subject  corto_select fluent methods
  66. subject  corto_subscribe
  67. subject  corto_subscribe fluent methods
  68. subject  corto_unsubscribe
  69. subject  corto_publish

Corto API Reference


In-memory Store

API for accessing and populating the in-memory store.

The in-memory store is a thread-safe, high-performance hierarchical object store that is designed to store the current state of an application. The store implements familiar OOP concepts like inheritance and polymorphism, alongside with support for collections, composite and primitive types to provide a convenient environment for expressing application logic.

Once objects are in the store, they can be discovered and introspected. This enables connecting generic components to the store, like for example a REST API, that automatically provides access to the contents of the store.

The object store provides a simple but powerful security framework for restricting access to objects. The security framework is deeply embedded into the core, thus decreasing the performance penalty to a minimum.

All objects are strongly typed, meaning their types can't change after they are created, although dynamic programming is supported by the any type. Type information is stored in the in-memory store alongside regular objects. This enables using the regular store APIs to create and query the store for metadata.

The in-memory store provides refcounting-based memory management. To maintain its realtime characteristics, the store will not attempt to detect reference-cycles in realtime. It is up to the application to ensure that non-persistent objects do not contain cycles.

Objects can be updated and observed. Every lifecycle event triggers a notification that can be catched by an observer (or subscriber, see vstore). Creating, updating and deleting objects all trigger notifications. Applications can subscribe for a single object, an object scope (branch) or a (sub)tree of objects.

The in-memory store interacts with the virtual store when lifecycle events take place. When the value of an object updates, it will be synchronized with the virtual store. When an object is created or deleted, it will also be created or deleted in the virtual store.

Corto makes an important distinction between deleting an object and no longer having references to an object. When the last reference to an object is removed, an object may be removed from the in-memory store to conserve RAM, but it will still be in the virtual store. A consecutive lookup of the object will reinsert it into the in-memory store.

Objects in the store are first declared, then defined. Between declaring and defining an application has the opportunity to set the initial object value. This ensures that when observers receive a DEFINE notification, the object will be set to a valid value. This also allows an application to forward- declare objects, which enables declaratively creating object cycles.

When defining an object, the virtual store is queried for the last value of the object. This is also referred to as resuming an object. The initial value assigned by the application inbetween declaring and defining the object may be overwritten when the vstore has a previous state of the object. This enables transparent persisting & retrieving of objects.

Applications may use the corto_create function to create an object with default values. The corto_create function is essentially a convenience wrapper around corto_declare and corto_define. When an object is defined it acquires the VALID object state, indicating that the value of the object may be interpreted for application logic.

Multiple threads may attempt to set the initial value of an object. When the same object is declared by multiple threads, corto_declare ensures that only one thread will see the object in a not-VALID state. While the object is undefined, corto_declare will block for the other threads, until the thread that received the non-VALID object defines the object.

When changing the value of an object, an application must use corto_update_begin and corto_update_end, which write-locks an object. When calling corto_update_end an UPDATE notification is sent to all observers of the object.

The store provides lifecycle hooks for objects, which are callbacks defined on the type of an object that provide more control to an object over its lifecycle. An example of a hook is the construct callback, which is invoked when an object is defined. Another hook is the validate hook, which allows the object to verify if a new object value is valid.

Applications can define functions and methods in the store, which can be implemented in multiple languages. The store provides an APO ( invoke.h) for registering language bindings, which allows to insert custom logic when a function object is invoked. This enables components written in multiple languages to interact with each other in a single process, which can for example be utilized to import Lua or Python scripts, whilst abstracting from the language they are written in. By default store functions are implemented in C. The store uses libffi for dynamically invoking C functions.

corto_create


Create a new named object.

Equivalent to calling corto_declare + corto_define.

Signature

corto_object
corto_create(
    corto_object parent,
    const char *id,
    corto_type type)

parent

The parent for the new object.

id

The object id. If NULL, a random unique id is generated. A name may contain multiple elements, separated by the '/' character. If one or more elements do not yet exist, they are created with the specified type.

type

The type of the object to create.

return

The new object, NULL if failed.

See also

corto_declare


Declare a new object.

This function returns an object in the DECLARED state, which enables setting the object value before invoking the type constructor with corto_define. When the object already exists with the specified type, the existing object will be returned.

The function fails if the type initializer fails or if it violates constraints of the specified type on the state or type of the specified parent. The function also fails when the object already exists with a different type.

Scoped objects are added to the scope of their parent and have a unique id which makes them discoverable in the object store. When this function succeeds an DECLARE event is emitted.

This function will block if there is another thread that has declared, but not defined the same object. Once the other thread defines the object, the function will unblock, and return an object in the DEFINED state. The calling thread can (and should) check the state of the returned object using corto_check_state to determine if it needs to initialize the object. The same thread may declare an object multiple times before it is defined.

Signature

corto_object
corto_declare(
    corto_object parent,
    const char *id,
    corto_type type)

parent

The parent for the new object.

id

The object id. If NULL, a random unique id is generated. A name may contain multiple elements, separated by the '/' character. If one or more elements do not yet exist, they are created with the specified type.

type

The type of the object to create.

return

The new object, NULL if failed.

See also

corto_define


Define an object.

This function changes the state of an object to DEFINED. When an object is defined, the type constructor is invoked. If successful, an DEFINE event is emitted. The DEFINE event indicates the moment when the value of an object is ready to be interpreted by contexts other than the one where the object was being created.

This function may emit an RESUME event instead of DEFINE if a SINK mount indicates that it has a copy of the object available. In this case, the function will overwrite the initial object value with the value that the SINK mount provides.

This mechanism enables transparent persistency of objects. The value specified by the application is treated as an initial value which is overridden by the latest value of the SINK, which is typically some form of persistent storage.

This function will fail if the type constructor fails.

If the function fails, the object is left in an undefined, invalid state. An application can attempt again to define the object by calling corto_define again on the object after resolving the issue that caused it to fail.

Signature

int16_t
corto_define(
    corto_object o)

o

The object to be defined.

return

0 if success, nonzero if failed.

See also

corto_delete


Delete an object.

This function deletes an object. If the object was DEFINED, the type destructor will be invoked.

Deleting an object does not guarantee that its memory is freed, as there still may be references to the object. Once all references have been released, the object will be deallocated.

If a named object is deleted, all it's children will be recursively deleted as well, using a depth-first walk.

This function fails if the current context does not own the object.

Signature

int16_t
corto_delete(
    corto_object o)

o

The object to be deleted.

return

0 if success, nonzero if failed.

See also

corto_update


Update an object.

This function emits an UPDATE event for the specified object.

This function fails if the current context does not own the object or if the object passed to was not created with ATTR_OBSERVABLE.

Signature

int16_t
corto_update(
    corto_object o)

o

The object to be updated.

return

0 if success, nonzero if failed.

See also

corto_update_begin


Start updating an object.

This function locks the object for thread-safe updating. No event is emitted yet. This function must be followed up by corto_update_end or corto_update_cancel.

This function fails if the current context does not own the object or if the object passed to was not created with ATTR_OBSERVABLE.

Signature

int16_t
corto_update_begin(
    corto_object o)

o

The object to be updated.

return

0 if success, nonzero if failed.

See also

corto_update_end


Update an object.

This function emits an UPDATE event and must be called after either a successful call to corto_update_begin or corto_update_try. If the function is called without first calling corto_update_begin or corto_update_try the behavior is undefined. The function will unlock the object.

This function behaves like corto_define when the object is not yet defined, in that it defines the object, and may either emit DEFINE or RESUME, depending on whether a SINK mount has a copy of the object.

Signature

int16_t
corto_update_end(
    corto_object o)

o

The object to be updated.

return

0 if success, nonzero if failed.

See also

corto_update_cancel


Cancel updating an object.

This function unlocks the object without any other side-effects. The application is responsible for reversing any changes made to the object.

Signature

int16_t
corto_update_cancel(
    corto_object o)

o

The object for which the update must be cancelled.

return

0 if success, nonzero if failed.

See also

corto_invalidate


Invalidate an object.

This function emits an INVALIDATE event when a valid object is passed to it. This function is typically used to indicate that an object has gone stale, or that the constructor of the object has failed.

This function fails if the current context does not own the object.

Signature

int16_t
corto_invalidate(
    corto_object o)

o

The object to be invalidated

return

0 if success, nonzero if failed.

See also

corto_claim


Claim an object.

This function increases the reference count of an object, which will prevent it from being deallocated.

It is usually not needed to call this function manually. When setting a member of a reference type, use the corto_set_ref function.

Signature

int32_t
corto_claim(
    corto_object o)

o

The object of which to increase the reference count.

return

The reference count of the object after the operation.

See also

corto_release


Release an object.

This function decreases the reference count of an object. When the reference count reaches zero, it will be deallocated.

Signature

int32_t
corto_release(
    corto_object o)

o

The object of which to increase the reference count.

return

The reference count of the object after the operation.

See also

corto_typeof


Get the type of an object.

Signature

corto_type
corto_typeof(
    corto_object o)

o

The object for which to obtain the type.

return

The object type.

See also

corto_stateof


Obtain the current state mask of the object.

Object state changes as an object is declared, defined and ultimately deleted.

Signature

corto_state
corto_stateof(
    corto_object o)

o

The object of which to obtain the state.

return

The state mask of the current object.

See also

corto_attrof


Obtain the attribute mask of the object.

Object attributes are static after an object is declared.

Signature

corto_attr
corto_attrof(
    corto_object o)

o

The object of which to obtain the attributes.

return

The attribute mask of the current object.

See also

corto_isorphan


Check if an object is an orphan.

Orphans are objects that contain a reference to a parent object, but the parent object does not have the object in its scope.

Signature

bool
corto_isorphan(
    corto_object o)

o

The object to check

return

true if the object is an orphan. =

corto_isbuiltin


Check if an object is a builtin object.

Builtin objects are part of the corto runtime and are not located on the heap.

Signature

bool
corto_isbuiltin(
    corto_object o)

o

The object to check

return

true if the object is builtin.

corto_countof


The current reference count of the object.

This function should be used with caution, as it introduces dependencies on the underlying garbage collection mechanism. A valid use for this function would be in testcases, where it can be used to validate if an specific operation did not introduce any leaks.

Signature

int32_t
corto_countof(
    corto_object o)

o

The object for which to obtain the reference count.

return

The reference count of the object.

See also

corto_idof


Get the object id.

The object passed to this function must be created with CORTO_ATTR_NAMED. If an object without CORTO_ATTR_NAMED is passed to this function the behavior is undefined.

Signature

char*
corto_idof(
    corto_object o)

o

A named object for which to obtain the id.

return

The object id. The returned string is not owned by the application.

See also

corto_nameof


Get the object name.

The object passed to this function must be created with CORTO_ATTR_NAMED. If an object without CORTO_ATTR_NAMED is passed to this function the behavior is undefined.

The object name is the same as the object id, unless the 'nameof' function of a type is overridden, in which case the result of that function is used.

Object names are meant to provide a user friendly, though not necessarily unique way to refer to an object.

Signature

char*
corto_nameof(
    corto_id str,
    corto_object o)

str

An id buffer in which to store the name. If NULL, a corto-managed string is returned which may change with subsequent calls to corto_nameof and other functions that use the corto stringcache.

o

A named object for which to obtain the name.

return

The object name. If str is NULL, the returned string is not owned by the application. Otherwise, str is returned.

See also

corto_parentof


Get the parent of an object.

The object passed to this function must be created with CORTO_ATTR_NAMED. If an object without CORTO_ATTR_NAMED is passed to this function the behavior is undefined.

This function may return NULL if the corto root object is passed as argument. If

Signature

corto_object
corto_parentof(
    corto_object o)

o

The object for which to obtain the id.

return

The object id. The returned string is not owned by the application.

See also

corto_sourceof


Returns the source for an object.

Only objects created with CORTO_ATTR_PERSISTENT can explicitly set a source. If the object is not PERSISTENT and is an orphan the function will obtain the source of the parent. In all other scenarios the function will return NULL.

Signature

corto_object
corto_sourceof(
    corto_object o)

o

A valid object.

return

The source of the object.

See also

corto_lookup


Lookup an object.

This function looks up an object and obtains a reference to it. If the object is not loaded in the store but is provided by a mount, it will be resumed from the mount into the store. After the object is no longer needed, an application should call corto_release.

corto_lookup can be used to find overloaded functions by specifying an parameter list between parentheses that contains the required types. For example, to find a function called add with two int32 parameters, 'add(int32,int32)' can be specified in id.

The following operators can be used in the parameter list: & - The requested argument is a reference. && - The offered argument must be a reference. null - The requested argument is either a reference or a string (null value). ? - The type is unknown.

Signature

corto_object
corto_lookup(
    corto_object scope,
    const char *id)

scope

The scope in which to lookup the object.

id

An id expression (foo/bar) identifying the object to lookup.

return

The object if found, NULL if not found.

See also

corto_resolve


Resolve an object.

This function is similar to corto_lookup, but follows a set of rules that is used to lookup types. Note however that corto_resolve can be used to lookup any object, not just types.

The reason that types use a different set of lookup rules is to enable short identifiers for builtin types (int32, struct, class, etc) and to types / packages in the corto package. Because these are frequently used, using an optimized set of rules will reduce footprint of type identifiers, which can significantly impact memory usage and bandwidth usage that rely on exchange of type information.

The rules of corto_resolve are: 1. If the identifier starts with an '/', lookup in root and return result. 2. If not, look for the identifier in corto/lang. 3. If not found, look for the identifier in the specified scope. 4. If not found, look for the identifier in the parent of the current scope [repeat] 5. If not found, look for the identifier in /corto.

corto_resolve will never look twice in a path, so if scope is corto/lang, the function will only look in corto/lang once.

If the id expression contains {}, corto_resolve will create an anonymous object by deserializing the contents within {} according to the rules of the corto string format.

Signature

corto_object
corto_resolve(
    corto_object scope,
    const char *id)

scope

The scope in which to lookup the object.

id

An id expression (foo/bar) identifying the object to lookup.

return

The object if found, NULL if not found.

See also

corto_observe


Create an observer.

Observers enable an application to listen for events from the object store, such as objects that are being created, updated or deleted. Observers can observe a single object, an object scope or a subtree of objects. corto_observe accepts a parameter event of the corto_eventMask type, which has the following values:

Flag Value Kind Description
CORTO_DECLARE 0x1 infra Observe objects being forward declared.
CORTO_DEFINE 0x2 data Observe objects being defined.
CORTO_DELETE 0x4 data Observe objects being deleted.
CORTO_INVALIDATE 0x8 data Observe objects being invalidated.
CORTO_UPDATE 0x10 data Observe objects being updated.
CORTO_RESUME 0x20 infra Observe objects being resumed.
CORTO_SUSPEND 0x40 infra Observe objects being suspended.
CORTO_ON_SELF 0x80 scope Observe a single object.
CORTO_ON_SCOPE 0x100 scope Observe children of an object.
CORTO_ON_TREE 0x200 scope Observe children of an object recursively.
CORTO_ON_VALUE 0x400 async Observe value of an object (requires lock).
CORTO_ON_METAVALUE 0x800 async Observe metavalue of an object.
CORTO_ON_ANY 0xffff any Observe all notifications.

The flag kinds have the following meaning:

Kind Description
infra Inform application about (meta) data in the RAM object store.
data Inform application about data (CrUD) events.
scope Set the scope of a mask.
async Set whether the mask requires an object to be locked.
any Enable all flags.

The functionality of corto_observe is further extended by fluent methods. See corto_observe fluent methods). A call to corto_observe must always finish with the callback fluent method, which creates the observer and accepts a callback that will be invoked when a matching notification triggers.

Observers provide a very fast mechanism for delivering events. The tradeoff is that for an observer to work, objects must be stored in RAM, which is fine if you don't observe millions of objects at the same time.

If you want to observe big datasets, check out corto_subscribe which offers equivalent functionality, but does not require objects to be stored in RAM.

Signature

corto_observe__fluent
corto_observe(
    corto_eventMask event,
    corto_object observable)

event

A mask that specifies the events to observe.

observable

The object to observe.

corto_observe fluent methods


The following methods extend the functionality of corto_observe by appending them to a call like this: corto_observe(...).<method>(...). Multiple methods can be appended to the call, as long as the previous method returns an instance of corto_observe__fluent.

disabled

Create disabled observer.

Disabled observers allow an application to make modifications to the observer mask or observable, and to observe multiple objects using corto_observer_observe.

Signature

corto_observe__fluent
disabled(
    void)

dispatcher

Provide dispatcher for observer.

Dispatchers intercept events before they are delivered to an observer callback, which enables applications to implement custom event handlers. A common usecase for this is to forward events to a worker thread.

Signature

corto_observe__fluent
dispatcher(
    corto_dispatcher dispatcher)
dispatcher

A dispatcher object.

instance

Specify an instance.

Instances are passed to observer callbacks. They are typically used to pass the this variable when an observer is associated with a class.

Signature

corto_observe__fluent
instance(
    corto_object instance)
instance

A corto object.

type

Filter objects by type.

The observer will only trigger on objects of the specified type.

Signature

corto_observe__fluent
type(
    char *type)
type

A valid corto type identifier.

callback

Specify callback, create observer.

Provide a callback function that is invoked when a matching event occurs. This function returns a new observer based on the specified parameters.

Signature

___
callback(
    void(
    *r)(
    corto_observerEvent *))
callback

An observer callback function.

See also

corto_unobserve


Delete an observer.

No more events will be delivered to the callback after this function is called. Note that the observer object will not be deallocated if there are references to the object.

When there are still events in flight when this function is called (something that can happen when a dispatcher is pushing events to another thread) the application can prevent delivery of the event by checking the state of the observer object, which is part of the corto_observerEvent instance, by doing:

void myDispatcher_post(corto_observerEvent *e) {
    if (!corto_check_state(e->observer, CORTO_DELETED)) {
        corto_event_handle(e);
    } else {
        // Do nothing
    }
}

Signature

int16_t
corto_unobserve(
    corto_observer observer)

observer

An observer object.

return

0 if success, -1 if failed.

See also

corto_serialize


Serialize object to a registered serialization format.

This serializes an object and its metadata to a registered serialization format. Serialization formats are packages stored in driver/fmt.

Signature

char*
corto_serialize(
    corto_object o,
    const char *fmtId)

o

The object to serialize.

fmtId

The serialization format identifier (for example: text/json).

return

The serialized value.

See also

corto_deserialize


Deserialize object from a registered serialization format.

This deserializes a value in a registered serialization format to an object. The function accepts a pointer to an object reference, which may be NULL. If the pointer is NULL, a new object will be created.

If the pointer is not NULL and the serialized data does not match with the specified object identifier or type, the function will fail.

Signature

int16_t
corto_deserialize(
    void *o,
    const char *fmtId,
    const char *data)

o

Pointer to the object to deserialize into. Object may be NULL.

fmtId

The serialization format identifier (for example: text/json).

data

Value formatted in the specified serialization format.

return

0 if success, non-zero if failed.

See also

corto_serialize_value


Serialize object value to a registered serialization format.

This serializes an object value to a registered serialization format. This function does not serialize object metadata, like type and id. Serialization formats are packages stored in driver/fmt.

Signature

char*
corto_serialize_value(
    corto_object o,
    const char *fmtId)

o

The object to serialize.

fmtId

The serialization format identifier (for example: text/json).

return

The serialized value.

See also

corto_deserialize_value


Deserialize object value from a registered serialization format.

This deserializes a value in a registered serialization format to an object.

Signature

int16_t
corto_deserialize_value(
    corto_object o,
    const char *fmtId,
    const char *data)

o

The object to deserialize into.

fmtId

The serialization format identifier (for example: text/json).

data

Value formatted in the specified serialization format.

return

0 if success, non-zero if failed.

See also

corto_fmt_lookup


Obtain handle to a serialization format plugin.

This function provides a high(er) performance alternative to looking up serialization formats by id, by returning a handle to a contentType that can be reused.

Signature

corto_fmt
corto_fmt_lookup(
    const char *fmtId)

fmtId

The serialization format identifier.

return

Handle to a serialization format plugin. NULL if failed.

corto_read_begin


Read-lock object.

This guarantees that the object will not be modified while the application holds the readlock. Multiple threads may obtain a readlock at the same time.

Signature

int16_t
corto_read_begin(
    corto_object o)

o

The object to readlock.

return

0 if success, non-zero if failed.

See also

corto_read_end


Release readlock.

Release lock on an object previously locked by corto_read_begin.

Signature

int16_t
corto_read_end(
    corto_object o)

o

The object to unlock.

return

0 if success, non-zero if failed.

See also

corto_lock


Write-lock object.

This guarantees that the object will not be read while the application holds the writelock, and that no other threads are modifying the object. Only one thread may hold a writelock at the same time.

Signature

int16_t
corto_lock(
    corto_object o)

o

The object to readlock.

return

0 if success, non-zero if failed.

See also

corto_unlock


Release writelock.

Release lock on an object previously locked by corto_write_begin.

Signature

int16_t
corto_unlock(
    corto_object o)

o

The object to unlock.

return

0 if success, non-zero if failed.

See also

corto_set_attr


Set object attributes for the current thread.

This function sets the attributes of objects that will be created in the current thread. For valid attribute values see the corto/lang/attr type.

Attributes were introduced to reduce footprint of corto objects by disabling features that are not used. For example, if an object does not need to be observed, it can be created without the CORTO_ATTR_OBSERVABLE attribute.

Signature

corto_attr
corto_set_attr(
    corto_attr attr)

attr

A mask containing the attributes for the current thread.

return

The previous attribute mask for this thread.

See also

corto_get_attr


Get the object attributes for the current thread.

This function returns the current object attributes that are set for this thread.

Signature

corto_attr
corto_get_attr(
    void)

return

The object attributes for the current thread.

See also

corto_set_source


Set the source for the current thread.

Signature

corto_object
corto_set_source(
    corto_object source)

source

A valid object.

return

The previous source of the thread.

See also

corto_get_source


Get the source for the current thread.

Signature

corto_object
corto_get_source(
    void)

return

The source of the current thread.

See also

corto_login


Login to a new session.

A login creates a new session, identified by a session token. After logging in the session is not yet active. To activate a session, pass the session token to the corto_set_session function.

A typical example of a session token can be an API key.

Signature

char*
corto_login(
    const char *username,
    const char *password)

username

The username of the user logging in.

password

The password of the user logging in.

return

The session token if login is valid. NULL if the login failed.

See also

corto_logout


Logout of a session.

After logging out, a session token is no longer guaranteed to authenticate a user.

Signature

void
corto_logout(
    const char *token)

token

An existing session token.

See also

corto_set_session


Set active session.

This sets the global session variable for the corto process. All authorization requests will use the specified session token.

Certain corto mechanisms (like subscribers) are associated with their own session token that they obtained at creation time. This allows a corto process to be multi-tenant.

Signature

char*
corto_set_session(
    const char *token)

token

An existing session token.

return

The previous session token.

See also

corto_authorize


Authorize the current session for an action on an object.

Signature

bool
corto_authorize(
    corto_object object,
    corto_secure_actionKind action)

o

The object for which to authorize.

action

The action to authorize.

return

true when authorized, false when not authorized.

See also

corto_authorize_id


Authorize the current session for an action on an object identifier.

Signature

bool
corto_authorize_id(
    const char *id,
    corto_secure_actionKind access)

id

The object identifier for which to authorize.

action

The action to authorize.

return

true when authorized, false when not authorized.

See also

corto_useradd


Register a new user.

Signature

int16_t
corto_useradd(
    const char *userId,
    const char *password,
    const char *group,
    const char *home)

userId

The user identifier.

password

The password for the user.

group

The group of the user.

home

The home scope of the user.

return

0 when success, non-zero when failed.

See also

corto_userdel


Unregister a user.

Signature

int16_t
corto_userdel(
    const char *userId)

userId

The user identifier.

return

0 when success, non-zero when failed.

See also

corto_secured


Test if process is secured.

This function provides a quick check to see if the process is secured. If the process is not secured, security-related functions will fail, and all requests for authorization are disabled.

Signature

bool
corto_secured(
    void)

return

true when secured, false when not secured.

corto_check_state


Check if an object is of a specified state.

Object state changes as an object is declared, defined and ultimately deleted.

Signature

bool
corto_check_state(
    corto_object o,
    corto_state state)

o

The object for which to check the state.

state

The state to look for.

return

true if the object is in the specified state, otherwise false.

See also

corto_check_attr


Check if an object is of a specified attribute.

Object attributes are static after an object is declared.

Signature

bool
corto_check_attr(
    corto_object o,
    corto_attr attr)

o

The object for which to check the attribute.

state

The attribute to look for.

return

true if the object has the specified attribute, otherwise false.

See also

corto_copy


Deep-copy value of source object to destination object.

The function accepts a pointer to an object reference. If the pointer points to a NULL value, the function will create a new object.

If the pointer contains a reference to an object, the function will verify if the type of the destination object is compatible with the source object. If it is not compatible, the function will fail.

Signature

int16_t
corto_copy(
    corto_object *dst,
    corto_object src)

dst

A pointer to the destination object.

src

The source object.

return

0 if success, non-zero if failed.

corto_compare


Compare value of two objects.

This function can be used to perform ordering on objects, as it will return whether objects are lesser, equal or larger than the other object.

Signature

int
corto_compare(
    corto_object o1,
    corto_object o2)

o1

The object to compare.

o2

The object to compare with.

return

0 if equal, 1 if o1 is larger than o2, -1 if o1 is smaller than o2.

corto_instanceof


Check if object is an instance of a specified type.

This function returns true when types exactly match, when o is of a type that is a subtype of type, when o is of a type that implements type, and when o is of target{type}.

Signature

bool
corto_instanceof(
    corto_type type,
    corto_object o)

type

The type against which to check.

o

The object to check.

return

true if o is an instance of type, otherwise false.

See also

corto_type_instanceof


Check if objects of a type are an instance of another type.

Signature

bool
corto_type_instanceof(
    corto_type type,
    corto_type valueType)

type

The type against which to check.

valueType

The type to check.

return

true if objects of valueType are an instance of type, otherwise false.

See also

corto_fullpath


Obtain a full path identifier to an object.

This function returns the shortest path that will lead to resolving the object using a corto_resolve where the root is specified as scope.

In practice this means that for objects in corto/lang it will only return the object id (int32) while for all other objects the function will a forward slash ('/') separated list of ids as obtained by corto_idof (/grandparent/parent/object).

Signature

char*
corto_fullpath(
    corto_id str,
    corto_object o)

str

An id buffer in which to store the id. If NULL, a corto-managed string is returned which may change with subsequent calls to corto_fullpath and other functions that use the corto stringcache.

o

The object for which to obtain the id.

return

The full path. If str is NULL, the returned string is not owned by the application. Otherwise, str is returned.

See also

corto_path


Obtain a relative path identifier to an object.

This function returns the shortest path from the specified from object to the to object, separated by sep. If to is a parent of from, this function will insert the appropriate number of '..' operators. This function uses corto_idof to determine the object ids.

The result of this function can be used with corto_lookup to lookup the to object, where from is specifed as scope and result as id.

If NULL is specified for from, an initial forward slash will be added to the resulting path. If root_o is specified for from, no initial slash will be added to the resulting path.

Signature

char*
corto_path(
    corto_id str,
    corto_object from,
    corto_object to,
    const char *sep)

str

An id buffer in which to store the id. If NULL, a corto-managed string is returned which may change with subsequent calls to corto_fullpath and other functions that use the corto stringcache.

from

The object from the path should be offset.

o

The object to which to generate the path.

sep

The path separator.

return

The path. If str is NULL, the returned string is not owned by the application. Otherwise, str is returned.

See also

corto_childof


Check if object is a child of the specified parent.

The objects passed to this function must be created with CORTO_ATTR_NAMED. If an object without CORTO_ATTR_NAMED is passed to this function the behavior is undefined.

Signature

bool
corto_childof(
    corto_object p,
    corto_object o)

p

The parent object.

o

The child object.

return

true if o is a child of p, otherwise false.

See also

corto_owned


Check if object is owned by current thread.

Corto uses this function to check if a thread is allowed to change an object through corto_update or corto_delete functions. The rules for sourceship are as follows:

  • If the object source is NULL, the object is owned by the application. A SOURCE mount will not be able to modify the object. 2. If the object source is not NULL and not an instance of corto/vstore/mount, the rule 1 applies. This mode can be used to emit notifications from a non-mount instance without an observer for that instance receiving the notification. 3. If the object source is an instance of corto/vstore/mount, the mount owns the object. If the mount is a SINK, it shares sourceship with the application. If the mount is a SOURCE, only that mount will be able to change the object.

The source is determined as specified by corto_sourceof.

Signature

bool
corto_owned(
    corto_object o)

o

A valid object.

return

The source of the object.

See also

corto_scope_size


Returns the number of child objects in a scope.

The objects passed to this function must be created with CORTO_ATTR_NAMED. If an object without CORTO_ATTR_NAMED is passed to this function the behavior is undefined.

This function must be used with care as it only returns number of objects that are currently loaded in the object store. If there are mounted objects in this scope that are not loaded in the store they will not be counted. To obtain an accurate count, use corto_select().count().

Signature

uint32_t
corto_scope_size(
    corto_object o)

o

A named object.

return

The number of objects in the scope of the object.

corto_scope_claim


Returns a sequence with the objects in the current scope.

The object passed to this function must be created with CORTO_ATTR_NAMED. If an object without CORTO_ATTR_NAMED is passed to this function the behavior is undefined.

This function must be used with care as it only returns objects that are currently loaded in the object store. If there are mounted objects in this scope that are not loaded in the store they will not be returned. To obtain a full list of objects count, use corto_select().iter_objects().

Signature

corto_objectseq
corto_scope_claim(
    corto_object o)

o

A named object.

return

A sequence with the objects in the scope of the object.

See also

corto_scope_release


Release a sequence obtained by corto_scope_claim.

Signature

void
corto_scope_release(
    corto_objectseq scope)

scope

A sequence obtained by corto_scope_claim.

See also

corto_scope_walk


Invoke a callback for each object in a scope.

The object passed to this function must be created with CORTO_ATTR_NAMED. If an object without CORTO_ATTR_NAMED is passed to this function the behavior is undefined.

Usage of this function is generally NOT recommended as it locks the scope which is a very intrusive operation. The lock is still being held when the action is called, so care must be taken not to introduce any deadlocks while in the action.

Use this function only for fast, low-level operations. For all other operations that need to walk a scope, use the safer corto_scope_claim and corto_scope_release.

Signature

int16_t
corto_scope_walk(
    corto_object o,
    corto_scope_walk_cb action,
    void *userData)

o

A named object.

return

A sequence with the objects in the scope of the object.

See also

Virtual Store

API for accessing and populating the virtual store.

The virtual store is, as the name suggests, not an actual store, but provides uniform access to data from any number of 3rd party stores. Data in the virtual store can move transparently to and from the in-memory store when application interest emerges or goes away. This process is fully automated, and does not require explicit action on behalf of the application.

The virtual store is populated by 'mounts'. Mounts are entities which connect subtrees of objects into the virtual store, which is represented to the application as a single uniform tree. Operations on the virtual store are translated by the query engine to the appropriate mounts, which will then either retrieve or synchronize the requested operation from the query engine.

Subtrees provided by mounts may be mounted in different locations by different applications. The query engine automatically translates between local identifiers and mount identifiers, so that a mount does not require knowledge about how it connects to the virtual store.

The mount class provides a rich interface for interacting with many kinds of data. The interface is implemented as a set of overridable methods on the mount class which a mount may or may not implement, based on the capabilities of the underlying technology.

A mount can reply to a single request for data, be notified of subscriptions so it can provide realtime data, provide historical data, synchronize data from the store, batch data from the store, downsample data from the store, throttle an application (using an intelligent algorithm that evenly spaces delays across sampling periods), amongst others.

Mounts are, just like anything else, objects that are stored in the in-memory store. This means that mounts can be instantiated with the regular store API, and that mount configurations can be provided in any serialization format that corto supports (XML, JSON, CX, ...).

Applications can interact with the virtual store directly through the corto_select, corto_subscribe and corto_publish APIs. Rather than going through the object store, these functions communicate directly with the mounts.

Mounts use the same mechanisms to communicate with each other, which means that the in-memory store can be completely bypassed. This particularly speeds up scenarios where data is bridged, where two can forward directly from one to another. Mounts can optionally configure a serialization format, in which case corto will automatically serialize/deserialize data to the correct format when it arrives/leaves the mount. When two mounts communicate directly and the serialization format is the same, a quick pass-through will take place.

Mounts inherit from corto subscribers, which means that they use the same mechanisms to describe data that they synchronize. Subscribers in corto use a corto_query, which is a custom query format optimized for querying hierarchies. The two most important parts of a corto_query are the select and from fields. The select field specifies a filter that is matched against an object id. The from field specifies the location in the virtual store where the subscriber subscribes to. Identifiers of objects delivered to the subscriber will be relative to the from query field.

A mount uses the from field to determine where it will mount its data. This also ensures that data the mount receives is relative to its mount point, which allows a mount to abstract away from where it is mounted by the app.

corto_select


Single-shot query.

With corto_select an application can select a subset of objects using a corto identifier expression (parent, expr). The functionality of the corto_select function is extended with fluent methods (see corto_select fluent methods) that enable an application to further narrow down results and perform various operations on the objects.

The most common operation is to request an iterator to the matching objects which allows the application to iterate over the set one by one.

The corto_select function is designed to be an API that enables accessing large datasets with constrained resources. The iterative design of the API allows the corto mount implementations to feed data to the application one object at a time, so that even with large result sets, the memory of an application will not be exhausted. Furthermore the API has native support for pagination, which allows applications to further narrow down results.

The results returned by corto_select are in abitrary order, which is a result of the requirement of being able to deal with large datasets. Ordering results would require obtaining a full resultset before anything can be returned to the application, which is not scalable.

The performance of corto_select highly depends on the implementation of a mount. The backend provides as much information as possible upfront to the mount about which information is required, which allows a mount to prefetch/cache results. A mount may choose to implement such optimizations, but this is not enforced.

The function employs minimal locking on the object store while an application is iterating over a resultset. Outside of the corto_iter_next and corto_iter_hasNext calls no locks will be held, which enables applications to run corto_select queries concurrently and without disturbing other tasks in an application.

Signature

corto_select__fluent
corto_select(
    const char *expr,...)

expr

An expression matching one or more objects [printf-style format specifier].

corto_select fluent methods


The following methods extend the functionality of corto_select by appending them to a call like this: corto_select(...).<method>(...). Multiple methods can be appended to the call, as long as the previous method returns an instance of corto_select__fluent.

from

Specify a relative scope for the query.

Signature

corto_select__fluent
from(
    const char *scope)
scope

A scope identifier.

contentType

Request results in a specific contentType.

Signature

corto_select__fluent
contentType(
    const char *contentType)
contentType

A MIME identifier identifying a contentType.

offset

Enable pagination by specifying an object offset.

Signature

corto_select__fluent
offset(
    corto_uint64 offset)
offset

Specifies from which nth object results should be returned.

limit

Enable pagination by specifying a limit to the number of objects returned.

Signature

corto_select__fluent
limit(
    corto_uint64 limit)
limit

Specifies the total number of results that should be returned.

type

Filter results by type.

Signature

corto_select__fluent
type(
    const char *filter)
filter

An id expression matching one or more types.

instance

Filter out results from a specific instance (mount).

This is typically useful when using corto_select from a mount, and the mount does not want to invoke itself.

Signature

corto_select__fluent
instance(
    corto_object instance)
instance

The instance object.

mount

Only return results for a specific mount.

This is typically useful when using corto_select from a mount, and the mount does not want to invoke itself.

Signature

corto_select__fluent
mount(
    corto_mount mount)
instance

The instance object.

fromNow

Request historical data starting from the current time.

Signature

corto_select__fluent
fromNow(
    void)

fromTime

Request historical data starting from fixed timestamp.

Signature

corto_select__fluent
fromTime(
    corto_time t)
t

The timestamp from which to return historical data.

toNow

Request historical data until now.

Signature

corto_select__fluent
toNow(
    void)

toTime

Request historical data until a fixed timestamp.

Signature

corto_select__fluent
toTime(
    corto_time t)
t

The timestamp until which to return historical data.

forDuration

Request historical data for a specific time window.

Signature

corto_select__fluent
forDuration(
    corto_time t)
t

The duration of the time window.

slimit

Request historical data for a specific number of samples.

Signature

corto_select__fluent
slimit(
    uint64_t limit)
limit

The number of samples per object.

soffset

Request historical starting from a specific sample.

Signature

corto_select__fluent
soffset(
    uint64_t offset)
offset

The offset from which to return samples.

iter

Return an iterator to the requested results.

Results are returned as corto_result instances. A corto_result contains metadata and when a content type is specified, a serialized value of an object. When using this function, no objects are created.

Signature

int16_t
iter(
    corto_resultIter *iter_out)
iter_out

A pointer to an iterator object.

return

0 if success, -1 if failed.

resume

Resume objects into the object store.

This function will resume objects in the object store.

Signature

int16_t
resume(
    void)
return

0 if success, -1 if failed.

iter_objects

Return an iterator to the requested objects.

This function will return results as anonymous objects. No objects will be created in the object store.

Signature

int16_t
iter_objects(
    corto_objectIter *iter_out)
iter_out

A pointer to an iterator object.

return

0 if success, -1 if failed.

count

Return the number of objects for a query.

This function requires a walk over all the returned results to determine the total number of objects.

Signature

int64_t
count(
    void)
return

-1 if failed, otherwise the total number of objects.

corto_subscribe


Create a realtime query.

Subscribers enable an application to listen for for events from the object store and events that come directly from mounts. Subscribers receive only data events (DEFINE, UPDATE, DELETE).

The difference between subscribers and observers is that while observers provide a reference to an object, a subscriber returns a corto_result, which contains metadata about the object, and when requested, a serialized value.

This means that a subscriber does not require objects to be stored in the in-memory object store, which makes it a better API for working with large datasets.

Signature

corto_subscribe__fluent
corto_subscribe(
    const char *expr,...)

expr

An expression matching one or more objects [printf-style format specifier].

corto_subscribe fluent methods


The following methods extend the functionality of corto_subscribe by appending them to a call like this: corto_subscribe(...).<method>(...). Multiple methods can be appended to the call, as long as the previous method returns an instance of corto_subscribe__fluent.

from

Specify a relative scope for the subscriber.

Signature

corto_subscribe__fluent
from(
    const char *scope)
scope

A scope identifier.

disabled

Create disabled subscriber.

Disabled observers allow an application to make modifications to the event mask or expression, and to observe multiple expressions using corto_subscriber_subscribe.

Signature

corto_subscribe__fluent
disabled(
    void)

dispatcher

Provide dispatcher for subscriber.

Dispatchers intercept events before they are delivered to an subscriber callback, which enables applications to implement custom event handlers. A common usecase for this is to forward events to a worker thread.

Signature

corto_subscribe__fluent
dispatcher(
    corto_dispatcher dispatcher)
dispatcher

A dispatcher object.

instance

Specify an instance.

Instances are passed to subscriber callbacks. They are typically used to pass the this variable when an subscriber is associated with a class.

Signature

corto_subscribe__fluent
instance(
    corto_object instance)
instance

A corto object.

contentType

Request results in a specific contentType.

Signature

corto_subscribe__fluent
contentType(
    const char *contentType)
contentType

A MIME identifier identifying a contentType.

type

Filter objects by type.

The subscriber will only trigger on objects of the specified type.

Signature

corto_subscribe__fluent
type(
    const char *type)
type

A valid corto type identifier.

mount

Create a mount of the specified type.

Signature

___
mount(
    corto_class type,
    corto_mountPolicy *policy,
    const char *value)
type

A mount type.

policy

A mount policy.

value

A corto string to set additional members of the mount.

return

A new mount object

callback

Specify callback, create subscriber.

Provide a callback function that is invoked when a matching event occurs. This function returns a new subscriber based on the specified parameters.

Signature

___
callback(
    void(
    *r)(
    corto_subscriberEvent *))
callback

An subscriber callback function.

corto_unsubscribe


Delete a subscriber.

No more events will be delivered to the callback after this function is called. Note that the subscriber object will not be deallocated if there are references to the object.

When there are still events in flight when this function is called (something that can happen when a dispatcher is pushing events to another thread) the application can prevent delivery of the event by checking the state of the subscriber object, which is part of the corto_subscriberEvent instance, by doing:

void myDispatcher_post(corto_subscriberEvent *e) {
    if (!corto_check_state(e->subscriber, CORTO_DELETED)) {
        corto_event_handle(e);
    } else {
        // Do nothing
    }
}

Signature

int16_t
corto_unsubscribe(
    corto_subscriber subscriber,
    corto_object instance)

subscriber

A subscriber object.

return

0 if success, -1 if failed.

corto_publish


Publish event.

This function enables emitting events for objects that are not loaded in the RAM store. This allows for efficient routing of events between subscribers without the need to (de)marshall object values.

If the object is loaded in the RAM store, a call to corto_publish will demarshall the specified value into the object.

The function may only emit events of the data kind, which are DEFINE, UPDATE, INVALIDATE and DELETE. The other events are reserved for objects that are loaded in the RAM store.

Signature

int16_t
corto_publish(
    corto_eventMask event,
    const char *id,
    const char *type,
    const char *contentType,
    void *content)

event

The event to be emitted

id

A string representing the id of the object in the form of 'foo/bar'.

type

A string representing the id of the type as returned by corto_fullpath.

contentType

A string representing the content type (format) of the specified value.

value

A string (or binary value) representing the serialized value of the object.

return

0 if success, nonzero if failed.

See also