Skip to content

refactor(core): improve backend storage robustness, error handling, and unit test coverage - #535

Merged
hummeltech merged 7 commits into
openstreetmap:masterfrom
hummeltech:TestUpdatesAndImprovements
Oct 31, 2026
Merged

hummeltech merged 7 commits into
openstreetmap:masterfrom
hummeltech:TestUpdatesAndImprovements

Conversation

@hummeltech

@hummeltech hummeltech commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

This PR refactors core backend components across queue handling, socket protocol helpers, and storage backends (store_file, store_memcached, store_rados, store_ro_composite, store_ro_http_proxy). The primary goals are to eliminate static symbols/naming collisions, strengthen error checking, fix memory allocation edge cases, and significantly expand test harness capabilities and overall unit test coverage.


Key Changes

1. Queue & Worker Management (render_submit_queue, request_queue)
  • Exposed internal queue structures (qItem, speed_stat, speed_stats) and function prototypes (check_load, thread_main) in render_submit_queue.h to enable direct unit testing.
  • Fixed missing memory check cleanups in enqueue() to prevent leaks on allocation failures.
  • Corrected error logging in make_connection() to output human-readable socket error strings via gai_strerror().
  • Added explicit type casting ((struct request_queue *)calloc) for C++ compilation cleanliness.
  • Export display_rate() via render_submit_queue.h and remove duplicate definitions across render_expired, render_list, render_old, and render_speedtest.
2. Storage Backends & Thread Safety (store_*)
  • store_rados: Renamed file-scope qLock to rados_qLock to prevent symbol collisions across backends. Added NULL safety validation checks for ctx and ctx->io before executing Rados read/write/delete/expire/close operations.
  • store_ro_composite: Renamed internal tile_cache struct to store_ro_composite_tile_cache to resolve name clashes. Added Cairo surface status checks (cairo_surface_status) to safely handle PNG decoding errors and destroy intermediate surfaces without leaks.
  • store_ro_http_proxy: Renamed file-scope qLock to ro_http_proxy_mutex and tile_cache to ro_http_proxy_tile_cache. Added heap allocation failure checks when allocating path buffers.
  • store_memcached: Added explicit casts for store->storage_ctx to (memcached_st *) across read, stat, write, and delete routines.
3. Protocol Helpers & Defensive Checks (protocol_helper, parameterize_style)
  • Added guard clauses in send_cmd() to reject negative file descriptors before attempting socket operations, and validated socket types via getsockopt(..., SO_TYPE, ...).
  • Added NULL check for function_name in init_parameterization_function() to avoid segfaults when evaluating empty parameterizations.
4. Test Suite & Coverage Expansion (tests/)
  • Added and expanded unit test suites covering request_queue, render_submit_queue, protocol helpers, tile expiration, and storage backends (store_file, store_memcached, store_rados, store_ro_composite, store_ro_http_proxy, store_null).
  • Updated CMake build configurations to link STORE_LIBRARIES into the unit_tests executable and register regular expression checks for timestamp verifications.
  • Annotated unreachable guard paths with LCOV_EXCL_START / LCOV_EXCL_STOP markers for accurate lcov reporting.

Testing & Verification

  • All Catch2 unit tests pass (unit_tests).
  • Verified build and test suite execution via updated GitHub Actions workflow (build-and-test.yml).

@hummeltech hummeltech self-assigned this Oct 30, 2026
Comment thread src/store_memcached.c

memcached_xyzo_to_storagekey(xmlconfig, options, x, y, z, meta_path);
buf_raw = memcached_get(store->storage_ctx, meta_path, strlen(meta_path), &len, &flags, &rc);
buf_raw = memcached_get((memcached_st *)store->storage_ctx, meta_path, strlen(meta_path), &len, &flags, &rc);
Comment thread src/store_memcached.c

memcached_xyzo_to_storagekey(xmlconfig, options, x, y, z, meta_path);
buf = memcached_get(store->storage_ctx, meta_path, strlen(meta_path), &len, &flags, &rc);
buf = memcached_get((memcached_st *)store->storage_ctx, meta_path, strlen(meta_path), &len, &flags, &rc);
Comment thread src/store_memcached.c
snprintf(meta_path, PATH_MAX - 1, "%s/%d/%d/%d.meta", xmlconfig, x, y, z);

rc = memcached_set(store->storage_ctx, meta_path, strlen(meta_path), buf2, sz2, (time_t)0, (uint32_t)0);
rc = memcached_set((memcached_st *)store->storage_ctx, meta_path, strlen(meta_path), buf2, sz2, (time_t)0, (uint32_t)0);
Comment thread src/store_memcached.c
memcached_xyz_to_storagekey(xmlconfig, x, y, z, meta_path);

rc = memcached_delete(store->storage_ctx, meta_path, strlen(meta_path), 0);
rc = memcached_delete((memcached_st *)store->storage_ctx, meta_path, strlen(meta_path), 0);
Comment thread src/store_memcached.c
//TODO: deal with options
memcached_xyz_to_storagekey(xmlconfig, x, y, z, meta_path);
buf = memcached_get(store->storage_ctx, meta_path, strlen(meta_path), &len, &flags, &rc);
buf = memcached_get((memcached_st *)store->storage_ctx, meta_path, strlen(meta_path), &len, &flags, &rc);
Comment thread src/store_memcached.c
// memcached_get() does not return a CAS value, so a compare-and-swap cannot be used here
// (the previous code passed an uninitialised CAS token). Replace the existing item instead.
rc = memcached_replace(store->storage_ctx, meta_path, strlen(meta_path), buf, len, 0, flags);
rc = memcached_replace((memcached_st *)store->storage_ctx, meta_path, strlen(meta_path), buf, len, 0, flags);
Comment thread src/store_ro_composite.c
}

connection_string_primary = malloc(strlen(connection_string) - strlen("composite:{") - strlen(connection_string_secondary) + 1);
connection_string_primary = (char *)malloc(strlen(connection_string) - strlen("composite:{") - strlen(connection_string_secondary) + 1);
Comment thread src/store_ro_composite.c
}

connection_string_primary = malloc(strlen(connection_string) - strlen("composite:{") - strlen(connection_string_secondary) + 1);
connection_string_primary = (char *)malloc(strlen(connection_string) - strlen("composite:{") - strlen(connection_string_secondary) + 1);
- Export display_rate() via render_submit_queue.h and remove duplicate
  definitions across render_expired, render_list, render_old, and
  render_speedtest.
- Add Catch2 unit test coverage for display_rate formatting and log output.
Remove unused file-scope static variable max_load and make it local to
main(). The load limit is passed directly to spawn_workers(), which
manages load throttling via render_submit_queue. Also remove unneeded
sys_utils.h inclusion.
@codecov

codecov Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.47739% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.58%. Comparing base (c4e3e62) to head (43c6a03).
⚠️ Report is 66 commits behind head on master.

Files with missing lines Patch % Lines
src/store_rados.c 70.00% 9 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #535      +/-   ##
==========================================
+ Coverage   81.54%   89.58%   +8.04%     
==========================================
  Files          24       24              
  Lines        5645     5463     -182     
==========================================
+ Hits         4603     4894     +291     
+ Misses       1042      569     -473     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Ensure finish_workers() is invoked in unit_test_render_submit_queue.cpp
to prevent thread race conditions when verifying error logs.
@hummeltech hummeltech removed their assignment Oct 30, 2026
@hummeltech
hummeltech merged commit 3beec34 into openstreetmap:master Oct 31, 2026
40 checks passed
@hummeltech
hummeltech deleted the TestUpdatesAndImprovements branch October 31, 2026 03:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants