Repository: valkey-io/valkey
File: src/tls.c (C)

Code before:
static int tlsConfigure(void *priv, int reconfigure, int background) {
    serverTLSContextConfig *ctx_config = (serverTLSContextConfig *)priv;
    SSL_CTX *ctx = NULL;
    SSL_CTX *client_ctx = NULL;

    if (!reconfigure && valkey_tls_ctx) {
        return C_OK;
    }

    if (reconfigure) {
        serverLog(LL_DEBUG, background ? "Background TLS reconfiguration started" : "Reconfiguring TLS");
    } else {
        serverLog(LL_DEBUG, "Configuring TLS");
    }

    atomic_store_explicit(&lastTlsConfigureTime, server.ustime, memory_order_relaxed);

    if (tlsCreateContexts(ctx_config, &ctx, &client_ctx) == C_ERR) {
        if (background) {
            serverLog(LL_WARNING, "Background TLS reload failed");
        }
        return C_ERR;
    }

    if (background) {
        if (atomic_load_explicit(&tls_reload_pending, memory_order_relaxed)) {
            SSL_CTX_free(ctx);
            SSL_CTX_free(client_ctx);
            serverLog(LL_DEBUG, "TLS reload already pending, discarding result");
        } else {
            pending_tls_ctx = ctx;
            pending_tls_client_ctx = client_ctx;
            atomic_store_explicit(&tls_reload_pending, 1, memory_order_release);
            serverLog(LL_DEBUG, "Background TLS reload completed successfully");
        }
    } else {
        SSL_CTX_free(valkey_tls_ctx);
        SSL_CTX_free(valkey_tls_client_ctx);
        valkey_tls_ctx = ctx;
        valkey_tls_client_ctx = client_ctx;
        (void)tlsCheckMaterialsAndUpdateCache(ctx_config);
    }

    return C_OK;
}

/* Synchronous TLS configuration - blocks until complete.
 * Called from CONFIG SET commands and server initialization. */
static int tlsConfigureSync(void *priv, int reconfigure) {
    return tlsConfigure(priv, reconfigure, 0);
}

Review comment (performance):
If we are here, I think this means we have a newer parsed certificate, but we've updated all the cached values so the next run won't update the value. Either we shouldn't be updating the cached values, or we could use a mutex queue to have multiple inflight SSL_contexts to the main thread.

Code after:
static tlsPendingReload pending_reload = {0};
static pthread_mutex_t pending_reload_mutex = PTHREAD_MUTEX_INITIALIZER;

/* Attempt to configure/reconfigure TLS. This operation is atomic and will
 * leave the SSL_CTX unchanged if it fails.
 *
 * If reconfigure is true, always reconfigure; if false, only configure if
 * valkey_tls_ctx is NULL.
 *
 * If background is true, check for changes and do heavy work in background thread;
 * if false, do work synchronously and swap immediately.
 */
static int tlsConfigure(void *priv, int reconfigure, bool background) {
    serverTLSContextConfig *ctx_config = (serverTLSContextConfig *)priv;
    SSL_CTX *ctx = NULL;
    SSL_CTX *client_ctx = NULL;

    if (!reconfigure && valkey_tls_ctx) {
        return C_OK;
    }

    if (reconfigure) {
        serverLog(LL_DEBUG, background ? "Background TLS reconfiguration started" : "Reconfiguring TLS");
    } else {
        serverLog(LL_DEBUG, "Configuring TLS");
    }

    if (background && reconfigure) {
        tlsMaterialsMetadata new_metadata;
        captureMetadata(ctx_config, &new_metadata);

        if (!metadataChanged(&active_metadata, &new_metadata)) {
            serverLog(LL_DEBUG, "TLS reload skipped: materials unchanged");
            atomic_store_explicit(&lastTlsConfigureTime, server.ustime, memory_order_relaxed);
            return C_OK;
        }
        serverLog(LL_NOTICE, "TLS materials changed, reloading in background");

        if (tlsCreateContexts(ctx_config, &ctx, &client_ctx) == C_ERR) {
            serverLog(LL_WARNING, "Background TLS reload failed");
            return C_ERR;
        }

        pthread_mutex_lock(&pending_reload_mutex);
        if (pending_reload.ctx) {
            SSL_CTX_free(pending_reload.ctx);
            SSL_CTX_free(pending_reload.client_ctx);
            serverLog(LL_DEBUG, "Replacing previous pending TLS reload");
        }
        pending_reload.ctx = ctx;
        pending_reload.client_ctx = client_ctx;