ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_cache.c
Go to the documentation of this file.
1
9#include "mdl_cache.h"
10
11#include <stdint.h>
12#include <string.h>
13#include <time.h>
14
15#include "mdl_cache_internal.h"
16#include "mdl_hash.h"
17#include "ra8_attributes.h"
18
26
41internal_cache_find(mdl_cache_index_t* index, const char* url, uint64_t url_hash)
42{
43 for (uint16_t i = 0U; i < index->record_count; ++i) {
44 if ((index->records[i].url_hash == url_hash) && (strcmp(index->records[i].url, url) == 0)) {
45 return &index->records[i];
46 }
47 }
48 return nullptr;
49}
50
63{
64 if (index->record_count < (uint16_t)k_mdl_cache_record_max) {
65 mdl_cache_record_t* slot = &index->records[index->record_count];
66 index->record_count += 1U;
67 return slot;
68 }
69 uint16_t oldest = 0U;
70 for (uint16_t i = 1U; i < index->record_count; ++i) {
71 if (index->records[i].fetched_at < index->records[oldest].fetched_at) {
72 oldest = i;
73 }
74 }
75 return &index->records[oldest];
76}
77
93RA8_INTERNAL static int64_t internal_cache_age(int64_t fetched_at)
94{
95 const time_t now = time(nullptr);
96 if ((fetched_at < 0) || (now < (time_t)0)) {
97 return -1;
98 }
99 const int64_t current = (int64_t)now;
100 return (current >= fetched_at) ? (current - fetched_at) : 0;
101}
102
118{
119 const time_t now = time(nullptr);
120 return (now < (time_t)0) ? 0 : (int64_t)now;
121}
122
140RA8_INTERNAL static bool internal_cache_copy(char* destination, size_t capacity, const char* source)
141{
142 const size_t length = strlen(source);
143 if (length >= capacity) {
144 destination[0] = '\0';
145 return false;
146 }
147 memcpy(destination, source, length + 1U);
148 return true;
149}
150
173 mdl_cache_record_t* existing,
174 const char* url,
175 uint64_t url_hash,
176 uint64_t content_hash,
177 const char* relative_path,
178 const mdl_net_resp_t* response)
179{
180 mdl_cache_record_t next = {.url_hash = url_hash,
181 .content_hash = content_hash,
182 .fetched_at = internal_cache_now(),
183 .response_status = (uint16_t)response->status};
184 if (!internal_cache_copy(next.url, sizeof(next.url), url) ||
185 !internal_cache_copy(next.relative_path, sizeof(next.relative_path), relative_path) ||
186 !internal_cache_copy(next.etag, sizeof(next.etag), response->etag) ||
188 sizeof(next.last_modified),
189 response->last_modified)) {
190 return false;
191 }
192 mdl_cache_record_t* destination = (existing != nullptr) ? existing : internal_cache_slot(index);
193 *destination = next;
194 return true;
195}
196
221 const char* url,
222 const mdl_net_req_t* base_request,
223 mdl_cache_fetch_fn fetch,
224 void* fetch_context,
225 char* buffer,
226 size_t capacity,
227 size_t* out_length,
228 mdl_net_resp_t* response)
229{
230 mdl_net_req_t request = *base_request;
231 request.if_none_match =
232 ((record != nullptr) && (record->etag[0] != '\0')) ? record->etag : nullptr;
233 request.if_modified_since =
234 ((record != nullptr) && (record->last_modified[0] != '\0')) ? record->last_modified : nullptr;
235 *out_length = 0U;
236 *response = (mdl_net_resp_t){};
237 return fetch(fetch_context, url, &request, buffer, capacity, out_length, response);
238}
239
251
273 const char* url,
274 char* buffer,
275 size_t capacity,
276 mdl_cache_result_t* result,
277 mdl_cache_lookup_t* lookup)
278{
279 *lookup = (mdl_cache_lookup_t){};
280 ra8_err_t error = priv_mdl_cache_load(cache, url, &lookup->paths, &result->index_rebuilt);
281 if (error != k_ra8_ok) {
282 return error;
283 }
284 const uint64_t url_hash = mdl_hash_str(url);
285 lookup->record = internal_cache_find(cache->index, url, url_hash);
286 lookup->held =
287 (lookup->record != nullptr) && (priv_mdl_cache_read_body(cache->storage,
288 &lookup->paths,
289 lookup->record,
290 buffer,
291 capacity,
292 &lookup->retained_length) == k_ra8_ok);
293 if (lookup->held) {
295 result->observed_status = lookup->record->response_status;
296 }
297 return k_ra8_ok;
298}
299
324 const mdl_net_req_t* base_request,
325 mdl_cache_fetch_fn fetch,
326 void* fetch_context,
327 char* buffer,
328 size_t capacity,
329 size_t* out_length,
330 mdl_net_resp_t* response)
331{
332 mdl_net_req_t request = *base_request;
333 request.if_none_match = nullptr;
334 request.if_modified_since = nullptr;
335 *out_length = 0U;
336 *response = (mdl_net_resp_t){};
337 const ra8_err_t error =
338 fetch(fetch_context, url, &request, buffer, capacity, out_length, response);
339 return ((error == k_ra8_ok) && (response->status == (long)k_cache_http_not_modified))
341 : error;
342}
343
366 const mdl_cache_paths_t* paths,
367 mdl_cache_record_t* record,
368 char* buffer,
369 size_t capacity,
370 size_t* out_length,
371 mdl_cache_result_t* result)
372{
373 ra8_err_t error =
374 priv_mdl_cache_read_body(cache->storage, paths, record, buffer, capacity, out_length);
375 if (error != k_ra8_ok) {
376 return error;
377 }
378 record->fetched_at = internal_cache_now();
379 record->response_status = (uint16_t)k_cache_http_not_modified;
380 error = priv_mdl_cache_save(cache, paths);
381 if (error == k_ra8_ok) {
382 result->body_reused = true;
383 result->observed_status = (uint16_t)k_cache_http_not_modified;
384 }
385 return error;
386}
387
412 const mdl_cache_paths_t* paths,
413 mdl_cache_record_t* existing,
414 const char* url,
415 const char* buffer,
416 size_t length,
417 const mdl_net_resp_t* response,
418 mdl_cache_result_t* result)
419{
420 if ((response->status < (long)k_cache_http_success_min) ||
421 (response->status > (long)k_cache_http_success_max) ||
422 (response->status > (long)k_cache_http_status_max) || (length == 0U)) {
424 }
425 const uint64_t url_hash = mdl_hash_str(url);
426 const uint64_t content_hash = mdl_hash_bytes(buffer, length);
427 char relative[k_mdl_relpath_max];
429 paths,
430 url_hash,
431 content_hash,
432 buffer,
433 length,
434 relative,
435 sizeof(relative));
436 if (error != k_ra8_ok) {
437 return error;
438 }
440 existing,
441 url,
442 url_hash,
443 content_hash,
444 relative,
445 response)) {
447 }
448 error = priv_mdl_cache_save(cache, paths);
449 if (error == k_ra8_ok) {
450 result->observed_status = (uint16_t)response->status;
451 }
452 return error;
453}
454
481 const mdl_cache_lookup_t* lookup,
482 const char* url,
483 const mdl_net_req_t* base_request,
484 mdl_cache_fetch_fn fetch,
485 void* fetch_context,
486 char* buffer,
487 size_t capacity,
488 size_t* out_length,
489 mdl_net_resp_t* response,
490 mdl_cache_result_t* result)
491{
492 result->revalidated = true;
493 ra8_err_t error = internal_cache_fetch(lookup->held ? lookup->record : nullptr,
494 url,
495 base_request,
496 fetch,
497 fetch_context,
498 buffer,
499 capacity,
500 out_length,
501 response);
502 if (error != k_ra8_ok) {
503 return error;
504 }
505 if (response->status == (long)k_cache_http_not_modified) {
506 if (lookup->held) {
507 return internal_cache_finish_304(cache,
508 &lookup->paths,
509 lookup->record,
510 buffer,
511 capacity,
512 out_length,
513 result);
514 }
516 base_request,
517 fetch,
518 fetch_context,
519 buffer,
520 capacity,
521 out_length,
522 response);
523 if (error != k_ra8_ok) {
524 return error;
525 }
526 }
527 return internal_cache_publish(cache,
528 &lookup->paths,
529 lookup->record,
530 url,
531 buffer,
532 *out_length,
533 response,
534 result);
535}
536
538 const char* url,
539 const mdl_net_req_t* base_request,
540 mdl_cache_fetch_fn fetch,
541 void* fetch_context,
542 char* buffer,
543 size_t capacity,
544 size_t* out_length,
545 mdl_net_resp_t* response,
546 mdl_cache_result_t* result)
547{
548 if ((cache == nullptr) || (cache->storage == nullptr) || (cache->index == nullptr) ||
549 (cache->root == nullptr) || (url == nullptr) || (base_request == nullptr) ||
550 (fetch == nullptr) || (buffer == nullptr) || (capacity == 0U) || (out_length == nullptr) ||
551 (response == nullptr) || (result == nullptr)) {
553 }
554 *out_length = 0U;
555 *response = (mdl_net_resp_t){};
556 *result = (mdl_cache_result_t){.age_seconds = -1};
557 mdl_cache_lookup_t lookup;
558 ra8_err_t error = internal_cache_prepare(cache, url, buffer, capacity, result, &lookup);
559 if (error != k_ra8_ok) {
560 return error;
561 }
562 const bool validators =
563 lookup.held && ((lookup.record->etag[0] != '\0') || (lookup.record->last_modified[0] != '\0'));
564 if (lookup.held && !cache->refetch && !validators) {
565 *out_length = lookup.retained_length;
566 result->body_reused = true;
567 return k_ra8_ok;
568 }
569 return internal_cache_network(cache,
570 &lookup,
571 url,
572 base_request,
573 fetch,
574 fetch_context,
575 buffer,
576 capacity,
577 out_length,
578 response,
579 result);
580}
static ra8_err_t internal_cache_prepare(mdl_cache_t *cache, const char *url, char *buffer, size_t capacity, mdl_cache_result_t *result, mdl_cache_lookup_t *lookup)
Load one host index and verify any retained exact-URL entity.
Definition mdl_cache.c:272
static bool internal_cache_record_response(mdl_cache_index_t *index, mdl_cache_record_t *existing, const char *url, uint64_t url_hash, uint64_t content_hash, const char *relative_path, const mdl_net_resp_t *response)
Update or insert one freshly published body record.
Definition mdl_cache.c:172
mdl_cache_http_t
HTTP response bounds used by the cache state machine.
Definition mdl_cache.c:20
@ k_cache_http_not_modified
Conditional reuse response.
Definition mdl_cache.c:23
@ k_cache_http_success_max
Last successful status.
Definition mdl_cache.c:22
@ k_cache_http_status_max
Last canonical HTTP status.
Definition mdl_cache.c:24
@ k_cache_http_success_min
First successful status.
Definition mdl_cache.c:21
static ra8_err_t internal_cache_fetch(const mdl_cache_record_t *record, const char *url, const mdl_net_req_t *base_request, mdl_cache_fetch_fn fetch, void *fetch_context, char *buffer, size_t capacity, size_t *out_length, mdl_net_resp_t *response)
Issue a cache-controlled request with selected validators.
Definition mdl_cache.c:220
static int64_t internal_cache_now(void)
Capture the current epoch for one response observation.
Definition mdl_cache.c:117
static mdl_cache_record_t * internal_cache_find(mdl_cache_index_t *index, const char *url, uint64_t url_hash)
Locate one exact URL record.
Definition mdl_cache.c:41
static bool internal_cache_copy(char *destination, size_t capacity, const char *source)
Copy a complete bounded string without truncation.
Definition mdl_cache.c:140
static ra8_err_t internal_cache_finish_304(mdl_cache_t *cache, const mdl_cache_paths_t *paths, mdl_cache_record_t *record, char *buffer, size_t capacity, size_t *out_length, mdl_cache_result_t *result)
Finish a verified HTTP 304 observation.
Definition mdl_cache.c:365
static ra8_err_t internal_cache_network(mdl_cache_t *cache, const mdl_cache_lookup_t *lookup, const char *url, const mdl_net_req_t *base_request, mdl_cache_fetch_fn fetch, void *fetch_context, char *buffer, size_t capacity, size_t *out_length, mdl_net_resp_t *response, mdl_cache_result_t *result)
Fetch, resolve 304 semantics, and publish one network observation.
Definition mdl_cache.c:480
ra8_err_t mdl_cache_get_buf(mdl_cache_t *cache, const char *url, const mdl_net_req_t *base_request, mdl_cache_fetch_fn fetch, void *fetch_context, char *buffer, size_t capacity, size_t *out_length, mdl_net_resp_t *response, mdl_cache_result_t *result)
Fetch one document through the per-host persistent cache.
Definition mdl_cache.c:537
static ra8_err_t internal_cache_retry_unconditional(const char *url, const mdl_net_req_t *base_request, mdl_cache_fetch_fn fetch, void *fetch_context, char *buffer, size_t capacity, size_t *out_length, mdl_net_resp_t *response)
Retry one invalid 304 without conditional headers.
Definition mdl_cache.c:323
static mdl_cache_record_t * internal_cache_slot(mdl_cache_index_t *index)
Select a record slot, evicting the oldest observation when full.
Definition mdl_cache.c:62
static int64_t internal_cache_age(int64_t fetched_at)
Compute a nonnegative retained-observation age.
Definition mdl_cache.c:93
static ra8_err_t internal_cache_publish(mdl_cache_t *cache, const mdl_cache_paths_t *paths, mdl_cache_record_t *existing, const char *url, const char *buffer, size_t length, const mdl_net_resp_t *response, mdl_cache_result_t *result)
Publish and index one successful nonempty response body.
Definition mdl_cache.c:411
Bounded per-host HTTP document cache for the media downloader.
ra8_err_t(* mdl_cache_fetch_fn)(void *context, const char *url, const mdl_net_req_t *request, char *buffer, size_t capacity, size_t *out_length, mdl_net_resp_t *response)
Injected bounded GET callback used by the cache.
Definition mdl_cache.h:78
@ k_mdl_cache_record_max
Records retained per host.
Definition mdl_cache.h:26
Private binary-index and body I/O seams for mdl_cache.
ra8_err_t priv_mdl_cache_load(mdl_cache_t *cache, const char *url, mdl_cache_paths_t *paths, bool *rebuilt)
Prepare a host directory and load or recover its index.
ra8_err_t priv_mdl_cache_publish_body(mdl_storage_t *storage, const mdl_cache_paths_t *paths, uint64_t url_hash, uint64_t content_hash, const char *buffer, size_t length, char *relative_path, size_t relative_capacity)
Publish one new body under its immutable content-derived leaf.
ra8_err_t priv_mdl_cache_read_body(mdl_storage_t *storage, const mdl_cache_paths_t *paths, const mdl_cache_record_t *record, char *buffer, size_t capacity, size_t *out_length)
Read and hash-check one retained body into caller storage.
ra8_err_t priv_mdl_cache_save(mdl_cache_t *cache, const mdl_cache_paths_t *paths)
Transactionally publish the current host index.
Content-identity hashing (FNV-1a 64) for the media downloader's persistent library state.
uint64_t mdl_hash_bytes(const void *data, size_t len)
FNV-1a 64 hash of a byte range.
Definition mdl_hash.c:35
uint64_t mdl_hash_str(const char *s)
FNV-1a 64 hash of a NUL-terminated string (excluding the NUL).
Definition mdl_hash.c:40
@ k_mdl_relpath_max
Page path relative to the series dir.
Definition mdl_state.h:102
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Caller-owned workspace for one loaded host index.
Definition mdl_cache.h:54
mdl_cache_record_t records[k_mdl_cache_record_max]
Retained observations.
Definition mdl_cache.h:55
uint16_t record_count
Populated rows.
Definition mdl_cache.h:58
Prepared host paths and verified retained-entity state.
Definition mdl_cache.c:245
size_t retained_length
Verified retained body size.
Definition mdl_cache.c:248
bool held
Body exists and hash checks.
Definition mdl_cache.c:249
mdl_cache_paths_t paths
Derived host namespace.
Definition mdl_cache.c:246
mdl_cache_record_t * record
Exact URL record, or NULL.
Definition mdl_cache.c:247
Complete paths and host identity derived for one request.
One exact URL-keyed cached document observation.
Definition mdl_cache.h:37
char url[k_mdl_url_max]
Exact canonical request URL.
Definition mdl_cache.h:38
char etag[k_mdl_etag_max]
Last response ETag, or empty.
Definition mdl_cache.h:40
char last_modified[k_mdl_last_mod_max]
Last-Modified, or empty.
Definition mdl_cache.h:41
uint64_t url_hash
FNV identity accelerator.
Definition mdl_cache.h:42
uint16_t response_status
Last observed HTTP status.
Definition mdl_cache.h:45
int64_t fetched_at
Completion epoch seconds.
Definition mdl_cache.h:44
char relative_path[k_mdl_relpath_max]
Body leaf beneath the host dir.
Definition mdl_cache.h:39
Observable outcome of one cache lookup.
Definition mdl_cache.h:105
bool body_reused
Returned bytes came from verified storage.
Definition mdl_cache.h:108
bool revalidated
A network request was issued.
Definition mdl_cache.h:109
bool index_rebuilt
A corrupt index was discarded first.
Definition mdl_cache.h:110
int64_t age_seconds
Age before this operation, or -1 if unknown.
Definition mdl_cache.h:106
uint16_t observed_status
Network or retained status.
Definition mdl_cache.h:107
One non-reentrant cache binding over caller storage.
Definition mdl_cache.h:92
bool refetch
Force a network revalidation.
Definition mdl_cache.h:97
const char * root
Canonical cache root.
Definition mdl_cache.h:95
mdl_storage_t * storage
Injected portable storage binding.
Definition mdl_cache.h:93
mdl_cache_index_t * index
Caller-owned index workspace.
Definition mdl_cache.h:94
Per-request session parameters.
Definition mdl_net.h:43
const char * if_none_match
If-None-Match conditional header (ETag), or NULL.
Definition mdl_net.h:46
const char * if_modified_since
If-Modified-Since header (Last-Modified), or NULL.
Definition mdl_net.h:47
Per-transfer response metadata surfaced to the politeness governor.
Definition mdl_net.h:120
long status
Finished transfer's HTTP status, 0 if none.
Definition mdl_net.h:121
char etag[k_mdl_etag_max]
Raw ETag value, "" when absent.
Definition mdl_net.h:123
char last_modified[k_mdl_last_mod_max]
Raw Last-Modified value, "" when absent.
Definition mdl_net.h:124