Skip to content

Commit

Permalink
fixup! Implement Entity Tag (ETag) for resources
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielius1922 committed Jul 31, 2023
1 parent c3020b8 commit 16a8bee
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 52 deletions.
104 changes: 71 additions & 33 deletions api/oc_etag.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,29 @@ oc_etag_global(void)
return g_etag;
}

uint64_t
oc_etag_set_global(uint64_t etag)
{
if (etag == OC_ETAG_UNINITALIZED) {
etag = 1;
}
if (etag < g_etag) {
// TODO: handle wrap around = all resource etags must be reinitialized
OC_DBG("etag wrap around detected: %" PRIu64 " -> %" PRIu64, g_etag, etag);
}
return (g_etag = etag);
}

uint64_t
oc_etag_get(void)
{
uint64_t now = oc_clock_time();
if (now > g_etag) {
g_etag = now;
uint64_t etag = g_etag;
if (now > etag) {
etag = now;
}
g_etag += etag_random();
if (g_etag == OC_ETAG_UNINITALIZED) {
g_etag = 1;
}
return g_etag;
etag += etag_random();
return oc_etag_set_global(etag);
}

#ifdef OC_STORAGE
Expand All @@ -91,22 +102,26 @@ static bool
etag_iterate_resources(size_t device, etag_process_resource_fn_t process_fn,
void *data)
{
bool success = true;
if (device == 0) {
// platform resources
for (int type = 0; type < OCF_CON; ++type) {
oc_resource_t *platform_res = oc_core_get_resource_by_index(type, 0);
if (process_fn(platform_res, data) != 0) {
OC_ERR("failed to process platform resource(%s)",
oc_string(platform_res->uri));
return false;
success = false;
}
}
}

// core resources
for (int type = OCF_CON; type <= OCF_D; ++type) {
oc_resource_t *core_res = oc_core_get_resource_by_index(type, device);
process_fn(core_res, data);
if (process_fn(core_res, data) != 0) {
OC_ERR("failed to process core resource(%s)", oc_string(core_res->uri));
success = false;
}
}

// app resources
Expand All @@ -117,7 +132,7 @@ etag_iterate_resources(size_t device, etag_process_resource_fn_t process_fn,
}
if (process_fn(app_res, data) != 0) {
OC_ERR("failed to process dynamic resource(%s)", oc_string(app_res->uri));
return false;
success = false;
}
}

Expand All @@ -130,12 +145,12 @@ etag_iterate_resources(size_t device, etag_process_resource_fn_t process_fn,
}
if (process_fn(&col->res, data) != 0) {
OC_ERR("failed to process collection(%s)", oc_string(col->res.uri));
return false;
success = false;
}
}
#endif /* OC_COLLECTIONS */

return true;
return success;
}

static int
Expand Down Expand Up @@ -183,15 +198,24 @@ etag_store_encode(size_t device, void *data)
return 0;
}

bool
oc_etag_dump_for_device(size_t device)
{
long ret =
oc_storage_data_save(OC_ETAG_STORE_NAME, device, etag_store_encode, NULL);
if (ret <= 0) {
OC_ERR("failed to dump etag for device %zu", device);
return false;
}
return true;
}

bool
oc_etag_dump(void)
{
bool success = true;
for (size_t i = 0; i < oc_core_get_num_devices(); ++i) {
long ret =
oc_storage_data_save(OC_ETAG_STORE_NAME, i, etag_store_encode, NULL);
if (ret <= 0) {
OC_ERR("failed to dump etag for device %zu", i);
if (!oc_etag_dump_for_device(i)) {
success = false;
}
}
Expand Down Expand Up @@ -232,7 +256,7 @@ static int
etag_iterate_clear_etag(oc_resource_t *resource, void *data)
{
(void)data;
oc_resource_set_etag(resource, 0);
oc_resource_set_etag(resource, OC_ETAG_UNINITALIZED);
return 0;
}

Expand All @@ -243,8 +267,12 @@ etag_store_decode_etags(const oc_rep_t *rep, size_t device, void *data)
// rep
uint64_t *etag = (uint64_t *)data;
etag_update_from_rep_data_t rep_data = { rep, etag };
etag_iterate_resources(device, etag_iterate_update_resources_by_rep,
&rep_data);
bool ret = etag_iterate_resources(
device, etag_iterate_update_resources_by_rep, &rep_data);
// return value should always be true because etag_iterate_resources always
// returns 0
assert(ret);
(void)ret;
return 0;
}

Expand All @@ -259,40 +287,50 @@ etag_iterate_update_empty_etag(oc_resource_t *resource, void *data)
}

bool
oc_etag_load_from_storage(void)
oc_etag_load_from_storage(bool from_storage_only)
{
bool success = true;
// load g_etag and resource etags from storage
uint64_t etag = oc_clock_time();
for (size_t i = 0; i < oc_core_get_num_devices(); ++i) {
// clear all etags
etag_iterate_resources(i, etag_iterate_clear_etag, NULL);
if (!from_storage_only) {
// clear all etags
// return value not checked - etag_iterate_clear_etag always returns 0
bool ret = etag_iterate_resources(i, etag_iterate_clear_etag, NULL);
assert(ret);
(void)ret;
}

// load etags from storage
long ret = oc_storage_data_load(OC_ETAG_STORE_NAME, i,
etag_store_decode_etags, &etag);
if (ret <= 0) {
OC_ERR("failed to load etag for device %zu", i);
OC_ERR("failed to load etags for device %zu", i);
success = false;
}
}
g_etag = etag + etag_random();
if (g_etag == OC_ETAG_UNINITALIZED) {
g_etag = 1;
}
OC_DBG("g_tag: %" PRIu64, g_etag);

// update empty etags
for (size_t i = 0; i < oc_core_get_num_devices(); ++i) {
etag_iterate_resources(i, etag_iterate_update_empty_etag, NULL);
etag += etag_random();
oc_etag_set_global(etag);
OC_DBG("g_tag: %" PRIu64, oc_etag_global());

if (!from_storage_only) {
// update empty etags
for (size_t i = 0; i < oc_core_get_num_devices(); ++i) {
// return value not checked - etag_iterate_update_empty_etag always
// returns 0
bool ret =
etag_iterate_resources(i, etag_iterate_update_empty_etag, NULL);
assert(ret);
(void)ret;
}
}
return success;
}

bool
oc_etag_load_and_clear(void)
{
bool success = oc_etag_load_from_storage();
bool success = oc_etag_load_from_storage(false);
success = oc_etag_clear_storage() && success;
return success;
}
Expand Down
11 changes: 10 additions & 1 deletion api/oc_etag_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ extern "C" {
/** Get the global ETag value without modifying it. */
uint64_t oc_etag_global(void);

/** Set global ETag value */
uint64_t oc_etag_set_global(uint64_t etag);

/** Get the next global ETag value. */
uint64_t oc_etag_get(void);

Expand Down Expand Up @@ -71,10 +74,16 @@ bool oc_etag_clear_storage(void);
* load other stores and the resources of device 0 will be updated by calling
* oc_etag_get(). The function will return false in this case.
*
* @param from_storage_only if true, only the ETag values from persistent
* storages are set and other resources' ETags are not changed
*
* @return true everything was succesfully loaded from persistent storage
* @return false otherwise
*/
bool oc_etag_load_from_storage(void);
bool oc_etag_load_from_storage(bool from_storage_only);

/** Dump ETags of given device to persisent storage. */
bool oc_etag_dump_for_device(size_t device);

#endif /* OC_STORAGE */

Expand Down
2 changes: 1 addition & 1 deletion api/oc_storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ oc_storage_data_load(const char *name, size_t device,
OC_ERR("cannot load from %s from store: cannot parse representation", name);
goto error;
}
if (decode(rep, device, decode_data) != 0) {
if (rep != NULL && decode(rep, device, decode_data) != 0) {
OC_ERR("cannot load from %s from store: cannot decode data", name);
oc_free_rep(rep);
goto error;
Expand Down
Loading

0 comments on commit 16a8bee

Please sign in to comment.