5.7. Persistence support

5.7.1. Anjay’s persistence in general

Anjay supports persistence of data to avs_commons generic stream (avs_stream_t). Underlying implementation of a stream may abstract any kind of storage access. avs_commons itself provides:

  • file streams,

  • network streams,

  • memory buffered streams.

Any of them can be used with Anjay’s persistence API. Additionally, one can easily adapt other types of storages to be used by persistence API, by implementing their own stream.

Persistence module is designed to abstract all endianness related issues, which makes persisted chunk of information on arbitrary architecture (having arbitrary endianness) easily restorable on any other architecture.

5.7.2. Persistence of pre-implemented objects/modules

Anjay’s pre-implemented objects (Security, Server, Access Control) and Attribute storage module all support persistence, for which the following functions can be used:

  • Security Object:

    • anjay_security_object_persist()

    • anjay_security_object_restore()

  • Server Object:

    • anjay_server_object_persist()

    • anjay_server_object_restore()

  • Access Control Object:

    • anjay_access_control_persist()

    • anjay_access_control_restore()

  • Attribute storage:

    • anjay_attr_storage_persist()

    • anjay_attr_storage_restore()

Note

All of the mentioned objects have complicated semantics, which is why you should refer to their documentation for more details on how persistence functions behave under different conditions.

5.7.3. Example

As an example we’ll modify the code from the Implementing standard Object tutorial. We would like to persist Object data when the LwM2M Client finishes its work and restore it on startup (if a valid persistence file exists).

#define PERSISTENCE_FILENAME "at2-persistence.dat"

int persist_objects(anjay_t *anjay) {
    avs_log(tutorial, INFO, "Persisting objects to %s", PERSISTENCE_FILENAME);

    avs_stream_t *file_stream =
            avs_stream_file_create(PERSISTENCE_FILENAME, AVS_STREAM_FILE_WRITE);

    if (!file_stream) {
        avs_log(tutorial, ERROR, "Could not open file for writing");
        return -1;
    }

    int result = -1;

    if (avs_is_err(anjay_security_object_persist(anjay, file_stream))) {
        avs_log(tutorial, ERROR, "Could not persist Security Object");
        goto finish;
    }

    if (avs_is_err(anjay_server_object_persist(anjay, file_stream))) {
        avs_log(tutorial, ERROR, "Could not persist Server Object");
        goto finish;
    }

    if (avs_is_err(anjay_attr_storage_persist(anjay, file_stream))) {
        avs_log(tutorial, ERROR, "Could not persist LwM2M attribute storage");
        goto finish;
    }

    result = 0;
finish:
    avs_stream_cleanup(&file_stream);
    return result;
}
int restore_objects_if_possible(anjay_t *anjay) {
    avs_log(tutorial, INFO, "Attempting to restore objects from persistence");
    int result;

    errno = 0;
    if ((result = access(PERSISTENCE_FILENAME, F_OK))) {
        switch (errno) {
        case ENOENT:
        case ENOTDIR:
            // no persistence file means there is nothing to restore
            return 1;
        default:
            // some other unpredicted error
            return result;
        }
    } else if ((result = access(PERSISTENCE_FILENAME, R_OK))) {
        // most likely file is just not readable
        return result;
    }

    avs_stream_t *file_stream =
            avs_stream_file_create(PERSISTENCE_FILENAME, AVS_STREAM_FILE_READ);

    if (!file_stream) {
        return -1;
    }

    result = -1;

    if (avs_is_err(anjay_security_object_restore(anjay, file_stream))) {
        avs_log(tutorial, ERROR, "Could not restore Security Object");
        goto finish;
    }

    if (avs_is_err(anjay_server_object_restore(anjay, file_stream))) {
        avs_log(tutorial, ERROR, "Could not restore Server Object");
        goto finish;
    }

    if (avs_is_err(anjay_attr_storage_restore(anjay, file_stream))) {
        avs_log(tutorial, ERROR, "Could not restore LwM2M attribute storage");
        goto finish;
    }

    result = 0;
finish:
    avs_stream_cleanup(&file_stream);
    return result;
}

Note

Persisting as well as restoring functions MUST be both called in the same order because objects’ data is being stored sequentially.

5.7.4. Persistence API

Please refer to the documentation of the avs_persistence component.