DataFed icon indicating copy to clipboard operation
DataFed copied to clipboard

Fix config access due to race condition

Open JoshuaSBrown opened this issue 11 months ago • 4 comments

PR Description

See issue for what triggered this PR #1241. The PR pulls out the Config structure a C struct with no safety mechanisms to prevent race conditions and memory corruption. The global config file is placed behind thread locks, in addition a switch is placed in front of initializing the Config structure to prevent excessive reads from the config file once the global state has been loaded into memory.

Tasks

  • [x] - A description of the PR has been provided, and a diagram included if it is a new feature.
  • [x] - Formatter has been run
  • [x] - CHANGELOG comment has been added
  • [x] - Labels have been assigned to the pr
  • [x] - A reviwer has been added
  • [x] - A user has been assigned to work on the pr
  • [x] - If new feature a unit test has been added

Summary by Sourcery

Refactor config loading and access to prevent race conditions and improve thread safety.

Bug Fixes:

  • Fixed a race condition when accessing configuration values.

Enhancements:

  • Improved thread safety for configuration access.
  • Refactored logging to use a dedicated logging module.
  • Introduced utility functions for UUID decoding and formatting.

Tests:

  • Added unit tests for the new config module and utility functions.

JoshuaSBrown avatar Jan 23 '25 07:01 JoshuaSBrown

Reviewer's Guide by Sourcery

This pull request addresses a race condition in the configuration access by using a read-write lock to protect the global configuration. It also refactors the configuration loading and access logic into a separate file, and removes the logging macros from the main source file.

Sequence diagram showing thread-safe configuration access

sequenceDiagram
    participant T1 as Thread 1
    participant T2 as Thread 2
    participant CM as ConfigManager
    participant C as Config

    Note over CM: Using read-write lock for thread safety

    T1->>CM: getConfigVal()
    activate CM
    CM->>CM: pthread_rwlock_rdlock()
    CM->>C: Read config value
    CM->>CM: pthread_rwlock_unlock()
    CM-->>T1: Return value
    deactivate CM

    T2->>CM: setConfigVal()
    activate CM
    CM->>CM: pthread_rwlock_wrlock()
    CM->>C: Write config value
    CM->>CM: pthread_rwlock_unlock()
    CM-->>T2: Return status
    deactivate CM

Class diagram showing the new configuration and utility structure

classDiagram
    class Config {
      +char repo_id[MAX_ID_LEN]
      +char server_addr[MAX_ADDR_LEN]
      +char pub_key[MAX_KEY_LEN]
      +char priv_key[MAX_KEY_LEN]
      +char server_key[MAX_KEY_LEN]
      +char user[MAX_ID_LEN]
      +char test_path[MAX_PATH_LEN]
      +char log_path[MAX_PATH_LEN]
      +char globus_collection_path[MAX_PATH_LEN]
      +size_t timeout
    }

    class ConfigManager {
      -Config g_config
      -bool config_loaded
      -pthread_rwlock_t config_rwlock
      +bool initializeGlobalConfig()
      +void allowConfigReinitialization()
      +bool getConfigVal(char* label, char* dest, size_t max_len)
      +bool setConfigVal(char* label, char* src)
      +Config createLocalConfigCopy()
    }

    class Util {
      +void uuidToStr(unsigned char* uuid, char* out)
      +bool decodeUUID(char* input, char* uuid)
    }

    class AuthzLog {
      +FILE* log_file
      +bool write_to_file
      +void AUTHZ_LOG_DEBUG()
      +void AUTHZ_LOG_INFO()
      +void AUTHZ_LOG_ERROR()
      +void AUTHZ_LOG_INIT()
      +void AUTHZ_LOG_CLOSE()
    }

    ConfigManager --> Config : manages
    note for ConfigManager "Thread-safe configuration management"

File-Level Changes

Change Details Files
Refactor configuration loading and access logic.
  • Introduce a new Config.h and Config.c file to encapsulate configuration logic.
  • Implement functions to load, validate, and access configuration values.
  • Use a read-write lock to protect the global configuration from race conditions.
  • Move the configuration loading logic from libauthz.c to Config.c.
  • Add functions to get and set config values.
repository/gridftp/globus5/authz/source/Config.h
repository/gridftp/globus5/authz/source/Config.c
Remove logging macros from libauthz.c.
  • Remove the logging macros from libauthz.c.
  • Include AuthzLog.h for logging functionality.
repository/gridftp/globus5/authz/source/libauthz.c
Add utility functions for UUID encoding and decoding.
  • Introduce a new Util.h and Util.c file to encapsulate UUID encoding and decoding logic.
  • Implement functions to convert a UUID to a string and decode a string to a UUID.
repository/gridftp/globus5/authz/source/Util.h
repository/gridftp/globus5/authz/source/Util.c
Update AuthzWorker to use the new config structure.
  • Update the AuthzWorker class to use the new Config struct instead of a pointer.
  • Update the AuthzWorker class to use the new getConfigVal function.
repository/gridftp/globus5/authz/source/AuthzWorker.cpp
repository/gridftp/globus5/authz/source/AuthzWorker.hpp
Update tests to use the new config structure.
  • Update the tests to use the new Config struct instead of a pointer.
  • Add new tests for the config and util files.
  • Update the CMakeLists.txt to include the new tests.
repository/gridftp/globus5/authz/tests/unit/test_AuthzWorker.cpp
repository/gridftp/globus5/authz/tests/unit/CMakeLists.txt
repository/gridftp/globus5/authz/tests/unit/test_Config.cpp
repository/gridftp/globus5/authz/tests/unit/test_Util.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an issue from a review comment by replying to it. You can also reply to a review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull request title to generate a title at any time. You can also comment @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in the pull request body to generate a PR summary at any time exactly where you want it. You can also comment @sourcery-ai summary on the pull request to (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the pull request to resolve all Sourcery comments. Useful if you've already addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull request to dismiss all existing Sourcery reviews. Especially useful if you want to start fresh with a new review - don't forget to comment @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

  • Contact our support team for questions or feedback.
  • Visit our documentation for detailed guides and information.
  • Keep in touch with the Sourcery team by following us on X/Twitter, LinkedIn or GitHub.

sourcery-ai[bot] avatar Jan 23 '25 07:01 sourcery-ai[bot]

@par-hermes format

JoshuaSBrown avatar Jan 23 '25 07:01 JoshuaSBrown

This PR is going to be split up into smaller pieces and merged more piecemeal as it has expanded beyond the initial scope.

JoshuaSBrown avatar Feb 01 '25 03:02 JoshuaSBrown

PRs this one is being broken into: https://github.com/ORNL/DataFed/pull/1274 https://github.com/ORNL/DataFed/pull/1279

JoshuaSBrown avatar Feb 01 '25 03:02 JoshuaSBrown