Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 36 additions & 91 deletions apteryx.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,62 +502,37 @@ apteryx_set (const char *path, const char *value)
}

bool
apteryx_cas_string (const char *path, const char *key, const char *value, uint64_t ts)
_apteryx_casf (uint64_t ts, const char *format, va_list vl)
{
char *full_path;
size_t len;
bool res = false;

/* Create full path */
if (key)
len = asprintf (&full_path, "%s/%s", path, key);
else
len = asprintf (&full_path, "%s", path);
if (len)
{
res = apteryx_cas (full_path, value, ts);
free (full_path);
}
if (!format)
return false;
char *path = g_strdup_vprintf (format, vl);
char *value = va_arg (vl, char *);
value = value ? g_strdup_vprintf (value, vl) : NULL;
bool res = apteryx_cas (path, value, ts);
g_free (value);
g_free (path);
return res;
}

bool
apteryx_set_string (const char *path, const char *key, const char *value)
{
return apteryx_cas_string (path, key, value, UINT64_MAX);
}

bool
apteryx_cas_int (const char *path, const char *key, int32_t value, uint64_t ts)
apteryx_casf (uint64_t ts, const char *format, ...)
{
char *full_path;
size_t len;
char *v;
bool res = false;

/* Create full path */
if (key)
len = asprintf (&full_path, "%s/%s", path, key);
else
len = asprintf (&full_path, "%s", path);
if (len)
{
/* Store as a string at the moment */
len = asprintf ((char **) &v, "%d", value);
if (len)
{
res = apteryx_cas (full_path, v, ts);
free ((void *) v);
}
free (full_path);
}
va_list vl;
va_start (vl, format);
bool res = _apteryx_casf (ts, format, vl);
va_end (vl);
return res;
}

bool
apteryx_set_int (const char *path, const char *key, int32_t value)
apteryx_setf (const char *format, ...)
{
return apteryx_cas_int (path, key, value, UINT64_MAX);
va_list vl;
va_start (vl, format);
bool res = _apteryx_casf (UINT64_MAX, format, vl);
va_end (vl);
return res;
}

typedef struct _get_data_t
Expand Down Expand Up @@ -636,53 +611,23 @@ apteryx_get (const char *path)
return value;
}

char *
apteryx_get_string (const char *path, const char *key)
{
char *full_path;
size_t len;
char *value = NULL;
char *str = NULL;

/* Create full path */
if (key)
len = asprintf (&full_path, "%s/%s", path, key);
else
len = asprintf (&full_path, "%s", path);
if (len)
{
if ((value = apteryx_get ((const char *) full_path)))
{
str = (char *) value;
}
free (full_path);
}
return str;
}

int32_t
apteryx_get_int (const char *path, const char *key)
int
apteryx_getf (const char *format, ...)
{
char *full_path;
size_t len;
char *v = NULL;
int value = -1;

/* Create full path */
if (key)
len = asprintf (&full_path, "%s/%s", path, key);
else
len = asprintf (&full_path, "%s", path);
if (len)
{
if ((v = apteryx_get (full_path)))
{
value = atoi ((char *) v);
free (v);
}
free (full_path);
}
return value;
va_list vl;
if (!format)
return 0;
va_start (vl, format);
char *path = g_strdup_vprintf (format, vl);
char *value = apteryx_get (path);
free (path);
if (!value)
return 0;
format = va_arg (vl, char *);
int res = vsscanf (value, format, vl);
free (value);
va_end (vl);
return res;
}

GNode *
Expand Down
116 changes: 86 additions & 30 deletions apteryx.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <glib.h>

/** Apteryx configuration
Expand Down Expand Up @@ -149,10 +150,28 @@ bool apteryx_dump (const char *path, FILE *fp);
* @return false if the path is invalid
*/
bool apteryx_set (const char *path, const char *value);
/** Helper to extend the path with the specified key */
bool apteryx_set_string (const char *path, const char *key, const char *value);
/** Helper to store a simple int at an extended path */
bool apteryx_set_int (const char *path, const char *key, int32_t value);

/**
* Set a path/value using standard printf format specifiers
* Example:
apteryx_setf ("/rules/%d/index", index, "%d", index);
apteryx_setf ("/rules/%d/name", index, "%s", name);
apteryx_setf ("/rules/%d/action", index, "%d", action);
* @param format variable list of path and value format specifiers
* @return true on a successful set
* @return false if the path is invalid or the path/value cannot be formatted
*/
bool apteryx_setf (const char *format, ...);

/** Deprecated helpers */
static inline bool apteryx_set_string (const char *path, const char *key, const char *value)
{
return apteryx_setf ("%s%s%s", path, key ? "/" : "", key ? : "", value);
}
static inline bool apteryx_set_int (const char *path, const char *key, int32_t value)
{
return apteryx_setf ("%s%s%s", path, key ? "/" : "", key ? : "", "%d", value);
}

/**
* Get a path/value from Apteryx
Expand All @@ -161,10 +180,33 @@ bool apteryx_set_int (const char *path, const char *key, int32_t value);
* @return NULL if the path is invalid
*/
char *apteryx_get (const char *path);
/** Helper to retrieve the value using an extended path based on the specified key */
char *apteryx_get_string (const char *path, const char *key);
/** Helper to retrieve a simple integer from an extended path */
int32_t apteryx_get_int (const char *path, const char *key);

/**
* Get a path/value using standard scanf format specifiers
* Example:
apteryx_getf ("/rules/%d/name", index, "%15s", name);
apteryx_getf ("/rules/%d/description", index, "%31[^\\0]", description);
apteryx_getf ("/rules/%d/action", index, "%d", &action);
* @param format variable list of path and value format specifiers
* @return number of successfully parsed items (0 if path value is NULL)
*/
int apteryx_getf (const char *format, ...);

/** Deprecated helpers */
static inline char *apteryx_get_string (const char *path, const char *key)
{
char _v[8192] = {};
if (apteryx_getf ("%s%s%s", path, key ? "/" : "", key ? : "", "%8191[^\\0]", _v))
return strdup(_v);
return NULL;
}
static inline int32_t apteryx_get_int (const char *path, const char *key)
{
int32_t _v = -1;
if (apteryx_getf ("%s%s%s", path, key ? "/" : "", key ?: "", "%d", &_v))
return _v;
return -1;
}

/**
* Get the last change timestamp of a given path
Expand All @@ -177,42 +219,56 @@ uint64_t apteryx_timestamp (const char *path);
* Set a path/value in Apteryx, but only if the existing
* value has not changed since the specified timestamp.
* Can be used for a Compare-And-Swap operation.
* Example: Set a value only if has not changed since read
uint64_t ts = apteryx_timestamp ("/interfaces/eth0/state");
char *state = apteryx_get ("/interfaces/eth0/state");
if (strcmp (state, "up") == 0 &&
apteryx_cas (ts, "/interfaces/eth0/state", "down"))
return true;
return false;
* @param path path to the value to set
* @param value value to set at the specified path
* @param ts timestamp to be compared to the paths last change time
* @return true on a successful set
* @return false if the set failed (errno == -EBUSY if timestamp comparison failed)
*/
bool apteryx_cas (const char *path, const char *value, uint64_t ts);

/**
* Set a path/value using standard printf format specifiers,
* but only if the existing value has not changed since
* the specified timestamp.
* Example: Safely reserve the next free row in a table
uint32_t index = 1;
while (index > 0) {
if (apteryx_cas_int (path, key, index, 0))
if (apteryx_casf (0, "/rules/%d/index", index))
break;
index++;
}
* Example: Safely updating a 32-bit bitmap
while (1) {
uint64_t ts = apteryx_timestamp (path);
uint32_t bitmap = 0;
char *value = apteryx_get (path);
if (value)
{
sscanf (value, "%"PRIx32, &bitmap);
free (value);
}
uint32_t bitmap = apteryx_getf (path, "%"PRIx32, &bitmap) ? bitmap : 0;
bitmap = (bitmap & ~clear) | set;
if (asprintf (&value, "%"PRIx32, bitmap) > 0) {
bool success = apteryx_cas (path, value, ts);
free (value);
if (success || errno != -EBUSY)
return success;
}
if (apteryx_casf (ts, "%"PRIx32, bitmap))
return;
}
* @param path path to the value to set
* @param value value to set at the specified path
* @param ts timestamp to be compared to the paths last change time
* @param format variable list of path and value format specifiers
* @return true on a successful set
* @return false if the set failed (errno == -EBUSY if timestamp comparison failed)
* @return false if the path is invalid or the path/value cannot be formatted
*/
bool apteryx_cas (const char *path, const char *value, uint64_t ts);
/** Helper to extend the path with the specified key */
bool apteryx_cas_string (const char *path, const char *key, const char *value, uint64_t ts);
/** Helper to store a simple int at an extended path */
bool apteryx_cas_int (const char *path, const char *key, int32_t value, uint64_t ts);
bool apteryx_casf (uint64_t ts, const char *format, ...);

/** Deprecated helpers */
static inline bool apteryx_cas_string (const char *path, const char *key, const char *value, uint64_t ts)
{
return apteryx_casf (ts, "%s%s%s", path, key ? "/" : "", key ? : "", value);
}
static inline bool apteryx_cas_int (const char *path, const char *key, int32_t value, uint64_t ts)
{
return apteryx_casf (ts, "%s%s%s", path, key ? "/" : "", key ? : "", "%d", value);
}

/**
* Helpers for generating and parsing an Apteryx tree.
Expand Down
Loading