state: remove unordered_map usage

Replacing unordered_map usage with list_head. This also includes the switch from
shared_ptr to a raw C pointer.

Yes, I moved around a lot of the functions, particularly in the header file, but
it was a mess and I was having difficulty keeping track of function
declarations. Please pardon the noise.

The refcnt variable was removed from zproxy_backend_state and
zproxy_service_state, since they should only ever be used directly in state.cpp.

Signed-off-by: Nicolás A. Ortega Froysa <nicolas.ortega@zevenet.com>
This commit is contained in:
Nicolás A. Ortega Froysa 2023-05-25 11:32:24 +02:00
parent 60afe68f7b
commit 81351bb97c
19 changed files with 431 additions and 346 deletions

View File

@ -18,19 +18,20 @@
#ifndef _ZPROXY_STATE_H_
#define _ZPROXY_STATE_H_
#include "config.h"
#include "list.h"
#include "session.h"
#include "zcu_log.h"
#include <sys/time.h>
#include <string>
#include <unordered_map>
#include <memory>
#include <ev.h>
#include <atomic>
#define TIMEOUT_SESSIONS 1
#define COUNTER_SESSIONS 10000
struct zproxy_backend_state;
struct zproxy_service_state;
struct zproxy_stats {
std::atomic<int32_t> http_2xx_hits {0}; ///< Total number of 2xx responses since initialization.
std::atomic<int32_t> http_3xx_hits {0}; ///< Total number of 3xx responses since initialization.
@ -41,24 +42,13 @@ struct zproxy_stats {
std::atomic<int32_t> conn_pending {0}; ///< Number of connections pending at the moment.
};
struct zproxy_backend_state {
zproxy_stats backend_stats;
uint32_t refcnt{1};
};
struct zproxy_service_state {
std::unordered_map<std::string, std::shared_ptr<zproxy_backend_state>> backends;
struct zproxy_sessions *sessions;
uint32_t refcnt{1};
};
struct zproxy_http_state {
list_head list;
uint32_t proxy_id{UINT32_MAX};
uint32_t refcnt{1};
struct list_head list;
uint32_t proxy_id;
uint32_t refcnt;
struct ev_timer timer;
zproxy_stats listener_stats;
std::unordered_map<std::string, std::shared_ptr<zproxy_service_state>> services;
struct zproxy_stats listener_stats;
struct list_head services;
};
/**
@ -85,9 +75,64 @@ inline void zproxy_stats_dump(const struct zproxy_stats *stats)
stats->conn_pending.load());
}
zproxy_stats *zproxy_stats_backend_get(
const struct zproxy_http_state *state,
const struct zproxy_backend_cfg *backend_cfg);
struct zproxy_stats *
zproxy_stats_backend_get(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
int zproxy_state_backend_add(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend);
/**
* Increment the backend stat for a given HTTP code.
*
* @param http_state HTTP state object that contains the backend stats.
* @param backend_cfg Configuration for the backend.
* @param code The HTTP code to increment.
*
* @return If the HTTP code is valid it will return 1. Return is -1 the HTTP
* code is invalid.
*/
int zproxy_stats_backend_inc_code(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg,
const int code);
/**
* Increment the connections established statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
void zproxy_stats_backend_inc_conn_established(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
/**
* Decrement the connections established statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
void zproxy_stats_backend_dec_conn_established(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
/**
* Increment the connections pending statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
int zproxy_stats_backend_inc_conn_pending(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
/**
* Decrement the connections pending statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
int zproxy_stats_backend_dec_conn_pending(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
int zproxy_stats_backend_get_pending(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
int zproxy_stats_backend_get_established(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
struct zproxy_sessions *
zproxy_state_get_service_sessions(const char *service,
const struct list_head *service_list);
/**
* Increment the listener stat for a given HTTP code.
@ -98,7 +143,8 @@ zproxy_stats *zproxy_stats_backend_get(
* @return If the HTTP code is valid it will return 1. Return is -1 the HTTP
* code is invalid.
*/
inline int zproxy_stats_listener_inc_code(struct zproxy_http_state *http_state, const int code)
inline int zproxy_stats_listener_inc_code(struct zproxy_http_state *http_state,
const int code)
{
if(code >= 500)
http_state->listener_stats.http_5xx_hits++;
@ -112,7 +158,6 @@ inline int zproxy_stats_listener_inc_code(struct zproxy_http_state *http_state,
return -1;
return 1;
}
/**
* Increment the listener stat for WAF hits.
*
@ -122,99 +167,25 @@ inline void zproxy_stats_listener_inc_waf(struct zproxy_http_state *http_state)
{
http_state->listener_stats.http_waf_hits++;
}
inline void zproxy_stats_listener_inc_conn_established(
struct zproxy_http_state *http_state)
inline void zproxy_stats_listener_inc_conn_established(struct zproxy_http_state *http_state)
{
http_state->listener_stats.conn_established++;
}
inline void zproxy_stats_listener_dec_conn_established(
struct zproxy_http_state *http_state)
inline void zproxy_stats_listener_dec_conn_established(struct zproxy_http_state *http_state)
{
http_state->listener_stats.conn_established--;
}
inline void zproxy_stats_listener_inc_conn_pending(
struct zproxy_http_state *http_state)
inline void zproxy_stats_listener_inc_conn_pending(struct zproxy_http_state *http_state)
{
http_state->listener_stats.conn_pending++;
}
inline void zproxy_stats_listener_dec_conn_pending(
struct zproxy_http_state *http_state)
inline void zproxy_stats_listener_dec_conn_pending(struct zproxy_http_state *http_state)
{
http_state->listener_stats.conn_pending--;
}
/**
* Increment the backend stat for a given HTTP code.
*
* @param http_state HTTP state object that contains the backend stats.
* @param backend_cfg Configuration for the backend.
* @param code The HTTP code to increment.
*
* @return If the HTTP code is valid it will return 1. Return is -1 the HTTP
* code is invalid.
*/
int zproxy_stats_backend_inc_code(struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg,
int code);
/**
* Increment the connections established statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
void zproxy_stats_backend_inc_conn_established(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
/**
* Decrement the connections established statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
void zproxy_stats_backend_dec_conn_established(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
/**
* Increment the connections pending statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
int zproxy_stats_backend_inc_conn_pending(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
/**
* Decrement the connections pending statistics for a given backend.
*
* @param http_state State object for the target listener.
* @param backend_cfg Configuration of the the backend to increment for.
*/
int zproxy_stats_backend_dec_conn_pending(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
int zproxy_stats_backend_get_pending(
const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
int zproxy_stats_backend_get_established(
const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
struct zproxy_stats *zproxy_stats_backend_get(
const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg);
void zproxy_state_purge(struct zproxy_proxy_cfg *proxy);
struct zproxy_http_state *zproxy_state_init(const struct zproxy_proxy_cfg *proxy);
struct zproxy_http_state *
zproxy_state_init(const struct zproxy_proxy_cfg *proxy);
void zproxy_state_purge(const struct zproxy_proxy_cfg *proxy);
/**
* @brief Looks up the corresponding zproxy_http_state for a given proxy ID.
*
@ -234,9 +205,5 @@ struct zproxy_http_state *zproxy_state_lookup(uint32_t proxy_id);
*/
void zproxy_state_release(struct zproxy_http_state **http_state);
void zproxy_state_cfg_update(struct zproxy_cfg *cfg);
void zproxy_state_backend_add(struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend);
struct zproxy_sessions *zproxy_state_get_session(const std::string &service,
std::unordered_map<std::string, std::shared_ptr<struct zproxy_service_state>> *service_map);
#endif

View File

@ -255,7 +255,8 @@ static enum ws_responses handle_get(const std::string &req_path,
return WS_HTTP_404;
}
zproxy_sessions *sessions =
zproxy_state_get_session(service_id, &state->services);
zproxy_state_get_service_sessions(service_id.c_str(),
&state->services);
if (!sessions) {
*resp_buf = zproxy_json_return_err("Couldn't find sessions for service %s in listener %d",
service_id.c_str(),
@ -325,7 +326,8 @@ static enum ws_responses handle_patch(const std::string &req_path,
return WS_HTTP_404;
}
zproxy_sessions *sessions =
zproxy_state_get_session(service_id, &state->services);
zproxy_state_get_service_sessions(service_id.c_str(),
&state->services);
if (!sessions) {
zproxy_state_release(&state);
*resp_buf = zproxy_json_return_err("Service %s not found.",
@ -413,7 +415,8 @@ static enum ws_responses handle_patch(const std::string &req_path,
return WS_HTTP_404;
}
zproxy_sessions *sessions =
zproxy_state_get_session(service_id, &state->services);
zproxy_state_get_service_sessions(service_id.c_str(),
&state->services);
if (!sessions) {
zproxy_state_release(&state);
*resp_buf = zproxy_json_return_err("Service %s not found.",
@ -452,7 +455,7 @@ static enum ws_responses handle_patch(const std::string &req_path,
}
for (auto &j : i.services) {
struct zproxy_sessions *sessions;
sessions = zproxy_state_get_session(j.name, &state->services);
sessions = zproxy_state_get_service_sessions(j.name, &state->services);
if (!sessions) {
*resp_buf = zproxy_json_return_err("Service %s doesn't exist.",
j.name);
@ -511,7 +514,8 @@ static enum ws_responses handle_delete(const std::string &req_path,
return WS_HTTP_404;
}
zproxy_sessions *sessions =
zproxy_state_get_session(service_id, &state->services);
zproxy_state_get_service_sessions(service_id.c_str(),
&state->services);
if (!sessions) {
zproxy_state_release(&state);
*resp_buf = zproxy_json_return_err("Service %s not found.",
@ -622,7 +626,8 @@ static enum ws_responses handle_put(const std::string &req_path,
return WS_HTTP_404;
}
zproxy_sessions *sessions =
zproxy_state_get_session(service_id, &state->services);
zproxy_state_get_service_sessions(service_id.c_str(),
&state->services);
if (!sessions) {
zproxy_state_release(&state);
*resp_buf = zproxy_json_return_err("Service %s not found.",

View File

@ -175,7 +175,9 @@ static int zproxy_http_request_head_rcv(struct zproxy_http_ctx *ctx)
list_for_each_entry(service, &cfg->service_list, list) {
if (zproxy_service_select(&stream->request, service)) {
stream->service_config = service;
stream->session = zproxy_state_get_session(service->name, &state->services);
stream->session =
zproxy_state_get_service_sessions(service->name,
&state->services);
break;
}
}

View File

@ -151,11 +151,12 @@ static json_t *serialize_service_sessions(const struct zproxy_service_cfg *servi
static json_t *serialize_service(const struct zproxy_service_cfg *service_cfg,
const struct zproxy_http_state *state)
{
struct zproxy_monitor_service_state *service_state;
const struct zproxy_monitor_service_state *service_monitor;
struct zproxy_sessions *service_sessions;
json_t *service;
service_state = zproxy_monitor_service_state_lookup(service_cfg->name);
if (!service_state)
service_monitor = zproxy_monitor_service_state_lookup(service_cfg->name);
if (!service_monitor)
return NULL;
service = json_object();
@ -163,9 +164,15 @@ static json_t *serialize_service(const struct zproxy_service_cfg *service_cfg,
serialize_service_backends(service_cfg, state));
json_object_set_new(service, "name", json_string(service_cfg->name));
json_object_set_new(service, "priority", json_integer(service_state->priority));
json_object_set_new(service, "priority", json_integer(service_monitor->priority));
service_sessions =
zproxy_state_get_service_sessions(service_cfg->name,
&state->services);
if (!service_sessions)
return NULL;
json_object_set_new(service, "sessions",
serialize_service_sessions(service_cfg, state->services.at(service_cfg->name)->sessions));
serialize_service_sessions(service_cfg,
service_sessions));
return service;
}
@ -313,6 +320,7 @@ char *zproxy_json_encode_glob_sessions(const struct zproxy_cfg *cfg)
char *buf;
const struct zproxy_proxy_cfg *proxy = NULL;
const struct zproxy_service_cfg *service = NULL;
struct zproxy_sessions *service_sessions;
struct zproxy_http_state *state = NULL;
json_t *json_obj = json_array();
@ -334,9 +342,15 @@ char *zproxy_json_encode_glob_sessions(const struct zproxy_cfg *cfg)
json_object_set_new(serv_obj, "name",
json_string(service->name));
service_sessions =
zproxy_state_get_service_sessions(service->name,
&state->services);
if (!service_sessions)
return NULL;
json_t *sess_arr =
serialize_service_sessions(service,
state->services.at(service->name)->sessions);
service_sessions);
json_object_set_new(serv_obj, "sessions", sess_arr);
json_array_append_new(serv_arr, serv_obj);
}

View File

@ -15,10 +15,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ev.h>
#include <assert.h>
#include <pthread.h>
#include <sys/syslog.h>
#include "config.h"
#include "zcu_log.h"
#include "zproxy.h"
#include "state.h"
#include "list.h"
@ -26,13 +33,88 @@
#include "session.h"
#include "proxy.h"
struct zproxy_backend_state {
struct list_head list;
char id[CONFIG_IDENT_MAX];
struct zproxy_stats backend_stats;
};
struct zproxy_service_state {
struct list_head list;
char name[CONFIG_IDENT_MAX];
struct list_head backends;
struct zproxy_sessions *sessions;
};
static LIST_HEAD(state_list);
static pthread_mutex_t list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static void zproxy_state_maintenance_cb(struct ev_loop *loop, ev_timer *timer, int events)
static struct zproxy_backend_state *
zproxy_state_backend_lookup(const struct list_head *backend_list,
const char *backend_id)
{
struct zproxy_backend_state *backend_state;
list_for_each_entry(backend_state, backend_list, list) {
if (strcmp(backend_state->id, backend_id) == 0)
return backend_state;
}
return NULL;
}
static struct zproxy_service_state *
zproxy_state_service_lookup(const struct list_head *service_list,
const char *name)
{
struct zproxy_service_state *service_state;
list_for_each_entry(service_state, service_list, list) {
if (strcmp(name, service_state->name) == 0)
return service_state;
}
return NULL;
}
static struct zproxy_http_state *_zproxy_state_lookup(uint32_t proxy_id)
{
struct zproxy_http_state *state;
list_for_each_entry(state, &state_list, list) {
if(state->proxy_id == proxy_id) {
return state;
}
}
return NULL;
}
struct zproxy_http_state *zproxy_state_lookup(uint32_t proxy_id)
{
struct zproxy_http_state *state;
pthread_mutex_lock(&list_mutex);
state = _zproxy_state_lookup(proxy_id);
state->refcnt++;
pthread_mutex_unlock(&list_mutex);
return state;
}
void zproxy_state_release(struct zproxy_http_state **http_state)
{
(*http_state)->refcnt--;
*http_state = NULL;
pthread_mutex_unlock(&list_mutex);
}
static void zproxy_state_maintenance_cb(struct ev_loop *loop, ev_timer *timer,
int events)
{
unsigned long counter = COUNTER_SESSIONS; // avoid CPU abuse of garbage recollector
struct zproxy_http_state *state;
struct zproxy_service_state *service_state;
Time::updateTime();
ev_timer_stop(loop, timer);
@ -40,9 +122,9 @@ static void zproxy_state_maintenance_cb(struct ev_loop *loop, ev_timer *timer, i
pthread_mutex_lock(&list_mutex);
state = container_of(timer, struct zproxy_http_state, timer);
for (auto & service : state->services) {
counter -= service.second->sessions->size;
zproxy_sessions_remove_expired(service.second->sessions);
list_for_each_entry(service_state, &state->services, list) {
counter -= service_state->sessions->size;
zproxy_sessions_remove_expired(service_state->sessions);
if (counter<=0)
break;
}
@ -51,49 +133,60 @@ static void zproxy_state_maintenance_cb(struct ev_loop *loop, ev_timer *timer, i
ev_timer_again(loop, timer);
}
struct zproxy_stats *zproxy_stats_backend_get(
const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
struct zproxy_stats *
zproxy_stats_backend_get(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
return &http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats;
const struct zproxy_service_state *service_state =
zproxy_state_service_lookup(&http_state->services, backend_cfg->service->name);
if (!service_state)
return NULL;
struct zproxy_backend_state *backend_state =
zproxy_state_backend_lookup(&service_state->backends, backend_cfg->runtime.id);
if (!backend_state)
return NULL;
return &backend_state->backend_stats;
}
static int __zproxy_stats_backend_get_pending(
const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
static int __zproxy_stats_backend_get_pending(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
return http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats.conn_pending;
const struct zproxy_stats *backend_stats =
zproxy_stats_backend_get(http_state, backend_cfg);
if (!backend_stats)
return -1;
return backend_stats->conn_pending;
}
static int __zproxy_stats_backend_get_established(
const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
static int __zproxy_stats_backend_get_established(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
return http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats.conn_established;
const struct zproxy_stats *backend_stats =
zproxy_stats_backend_get(http_state, backend_cfg);
if (!backend_stats)
return -1;
return backend_stats->conn_established;
}
int zproxy_stats_backend_get_established(
const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
int zproxy_stats_backend_get_established(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
return __zproxy_stats_backend_get_pending(http_state, backend_cfg) +
__zproxy_stats_backend_get_established(http_state, backend_cfg);
}
int zproxy_stats_backend_inc_code(struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg,
int code)
int zproxy_stats_backend_inc_code(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg,
const int code)
{
struct zproxy_stats *backend_stats =
&http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats;
zproxy_stats_backend_get(http_state, backend_cfg);
if (!backend_stats)
return -1;
if(code >= 500)
backend_stats->http_5xx_hits++;
else if(code >= 400)
@ -104,79 +197,83 @@ int zproxy_stats_backend_inc_code(struct zproxy_http_state *http_state,
backend_stats->http_2xx_hits++;
else
return -1;
return 1;
}
void zproxy_stats_backend_inc_conn_established(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
void zproxy_stats_backend_inc_conn_established(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats.conn_established++;
struct zproxy_stats *backend_stats =
zproxy_stats_backend_get(http_state, backend_cfg);
if (!backend_stats)
return;
backend_stats->conn_established++;
}
void zproxy_stats_backend_dec_conn_established(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
void zproxy_stats_backend_dec_conn_established(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats.conn_established--;
struct zproxy_stats *backend_stats =
zproxy_stats_backend_get(http_state, backend_cfg);
if (!backend_stats)
return;
backend_stats->conn_established--;
}
int zproxy_stats_backend_inc_conn_pending(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
int zproxy_stats_backend_inc_conn_pending(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
return ++http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats.conn_pending;
struct zproxy_stats *backend_stats =
zproxy_stats_backend_get(http_state, backend_cfg);
if (!backend_stats)
return -1;
return ++backend_stats->conn_pending;
}
int zproxy_stats_backend_dec_conn_pending(
struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
int zproxy_stats_backend_dec_conn_pending(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend_cfg)
{
return --http_state->services.at(backend_cfg->service->name)
->backends.at(backend_cfg->runtime.id)
->backend_stats.conn_pending;
struct zproxy_stats *backend_stats =
zproxy_stats_backend_get(http_state, backend_cfg);
if (!backend_stats)
return -1;
return --backend_stats->conn_pending;
}
struct zproxy_backend_state *zproxy_state_get_backend(
const std::unordered_map<std::string, std::shared_ptr<struct zproxy_backend_state>> *backend_state_map,
const struct zproxy_backend_cfg *backend)
{
const std::string id = std::string(backend->runtime.id);
auto backend_pair = backend_state_map->find(id);
if (backend_pair == backend_state_map->end())
return nullptr;
return backend_pair->second.get();
}
void zproxy_state_backend_init(const struct zproxy_service_cfg *service_cfg,
std::unordered_map<std::string, std::shared_ptr<zproxy_backend_state>> *backend_state_list)
static int zproxy_state_backend_init(const struct zproxy_service_cfg *service_cfg,
struct list_head *backend_list)
{
struct zproxy_backend_cfg *backend;
struct zproxy_backend_state *backend_state;
list_for_each_entry(backend, &service_cfg->backend_list, list) {
auto backend_state = zproxy_state_get_backend(backend_state_list, backend);
if (backend_state != nullptr) {
backend_state->refcnt++;
backend_state = zproxy_state_backend_lookup(backend_list,
backend->runtime.id);
if (backend_state)
continue;
backend_state = (struct zproxy_backend_state*)
calloc(1, sizeof(struct zproxy_backend_state));
if (!backend_state) {
zcu_log_print(LOG_ERR,
"Couldn't create backend state (OOM)");
return -1;
}
const std::string backend_id = std::string(backend->runtime.id);
auto new_backend_state = std::make_shared<zproxy_backend_state>();
auto it = make_pair(backend_id, std::move(new_backend_state));
backend_state_list->emplace(std::move(it));
snprintf(backend_state->id, CONFIG_IDENT_MAX, "%s",
backend->runtime.id);
list_add_tail(&backend_state->list, backend_list);
}
return 1;
}
void zproxy_state_backend_add(struct zproxy_http_state *http_state,
int zproxy_state_backend_add(const struct zproxy_http_state *http_state,
const struct zproxy_backend_cfg *backend)
{
struct zproxy_service_state *service_state;
@ -184,49 +281,61 @@ void zproxy_state_backend_add(struct zproxy_http_state *http_state,
struct zproxy_backend_state *backend_state;
pthread_mutex_lock(&list_mutex);
service_state = http_state->services.at(service_name).get();
backend_state = zproxy_state_get_backend(&service_state->backends, backend);
if (backend_state != nullptr) {
backend_state->refcnt++;
pthread_mutex_unlock(&list_mutex);
return;
service_state = zproxy_state_service_lookup(&http_state->services,
service_name);
if (!service_state) {
zcu_log_print(LOG_ERR, "Couldn't find service state %s.",
service_name);
return -1;
}
const std::string backend_id = std::string(backend->runtime.id);
backend_state = zproxy_state_backend_lookup(&service_state->backends,
backend->runtime.id);
if (backend_state) {
zcu_log_print(LOG_INFO, "Backend %s already exists.",
backend->runtime.id);
pthread_mutex_unlock(&list_mutex);
return 1;
}
auto new_backend_state = std::make_shared<zproxy_backend_state>();
auto it = make_pair(backend_id, std::move(new_backend_state));
service_state->backends.emplace(std::move(it));
backend_state = (struct zproxy_backend_state*)
calloc(1, sizeof(struct zproxy_backend_state));
if (!backend_state) {
zcu_log_print(LOG_ERR, "Couldn't create backend (OOM).");
return -1;
}
snprintf(backend_state->id, CONFIG_IDENT_MAX, "%s",
backend->runtime.id);
list_add_tail(&backend_state->list, &service_state->backends);
pthread_mutex_unlock(&list_mutex);
return 1;
}
struct zproxy_http_state *zproxy_state_init(const struct zproxy_proxy_cfg *proxy)
struct zproxy_http_state *
zproxy_state_init(const struct zproxy_proxy_cfg *proxy)
{
struct zproxy_http_state *state = nullptr;
struct zproxy_http_state *state_ptr;
struct std::shared_ptr<zproxy_service_state> service_state;
struct zproxy_service_state *service_state;
struct zproxy_service_cfg *service_cfg;
pthread_mutex_lock(&list_mutex);
list_for_each_entry(state_ptr, &state_list, list) {
if (proxy->id == state_ptr->proxy_id) {
state_ptr->refcnt++;
state = state_ptr;
break;
}
}
if (!state) {
state = new zproxy_http_state;
state = _zproxy_state_lookup(proxy->id);
if (state) {
state->refcnt++;
} else {
state = (struct zproxy_http_state*)
calloc(1, sizeof(struct zproxy_http_state));
if (!state) {
pthread_mutex_unlock(&list_mutex);
return NULL;
}
state->proxy_id = proxy->id;
INIT_LIST_HEAD(&state->services);
// Garbage recolector for expired sessions
// Garbage collector for expired sessions
ev_init(&state->timer, zproxy_state_maintenance_cb);
state->timer.repeat = TIMEOUT_SESSIONS;
ev_timer_again(zproxy_main.loop, &state->timer);
@ -235,49 +344,97 @@ struct zproxy_http_state *zproxy_state_init(const struct zproxy_proxy_cfg *proxy
}
list_for_each_entry(service_cfg, &proxy->service_list, list) {
auto service_state_pair = state->services.find(service_cfg->name);
if (service_state_pair == state->services.end()) {
service_state = std::make_shared<zproxy_service_state>();
service_state->sessions = zproxy_sessions_alloc(service_cfg);
state->services.emplace(make_pair(service_cfg->name, service_state));
} else {
service_state = service_state_pair->second;
service_state->refcnt++;
service_state = zproxy_state_service_lookup(&state->services,
service_cfg->name);
if (!service_state) {
service_state = (struct zproxy_service_state*)
calloc(1, sizeof(struct zproxy_service_state));
if (!service_state) {
pthread_mutex_unlock(&list_mutex);
return NULL;
}
service_state->sessions =
zproxy_sessions_alloc(service_cfg);
snprintf(service_state->name, CONFIG_IDENT_MAX, "%s",
service_cfg->name);
INIT_LIST_HEAD(&service_state->backends);
list_add_tail(&service_state->list, &state->services);
}
if (zproxy_state_backend_init(service_cfg,
&service_state->backends) < 0) {
return NULL;
}
zproxy_state_backend_init(service_cfg, &service_state->backends);
}
pthread_mutex_unlock(&list_mutex);
return state;
}
static void zproxy_backend_state_purge(struct zproxy_backend_state *backend_state)
{
list_del(&backend_state->list);
free(backend_state);
}
static void zproxy_service_state_purge(struct zproxy_service_state *service_state)
{
struct zproxy_backend_state *backend_state, *next;
zproxy_sessions_free(service_state->sessions);
list_for_each_entry_safe(backend_state, next, &service_state->backends, list)
zproxy_backend_state_purge(backend_state);
list_del(&service_state->list);
free(service_state);
}
static void zproxy_proxy_state_purge(struct zproxy_http_state *state)
{
struct zproxy_service_state *service_state, *next;
if (--state->refcnt > 0)
return;
list_for_each_entry_safe(service_state, next, &state->services, list)
zproxy_service_state_purge(service_state);
ev_timer_stop(zproxy_main.loop, &state->timer);
list_del(&state->list);
free(state);
}
void zproxy_state_purge(const struct zproxy_proxy_cfg *proxy)
{
struct zproxy_http_state *state;
pthread_mutex_lock(&list_mutex);
state = _zproxy_state_lookup(proxy->id);
if (state)
zproxy_proxy_state_purge(state);
pthread_mutex_unlock(&list_mutex);
}
static void zproxy_state_cfg_service_update(const struct zproxy_service_cfg *service,
struct zproxy_service_state *service_state)
{
const struct zproxy_backend_cfg *backend;
auto backend_state = service_state->backends.begin();
int found;
struct zproxy_backend_state *backend_state, *next;
bool found;
zproxy_session_delete_old_backends(service, service_state->sessions);
while (backend_state != service_state->backends.end()) {
found = 0;
list_for_each_entry_safe(backend_state, next, &service_state->backends,
list) {
found = false;
list_for_each_entry(backend, &service->backend_list, list) {
if (strcmp(backend->runtime.id, backend_state->first.c_str())) {
found = 1;
if (strcmp(backend->runtime.id, backend_state->id) == 0) {
found = true;
break;
}
}
if (!found) {
auto iter = backend_state;
backend_state++;
service_state->backends.erase(iter);
continue;
}
backend_state++;
if (!found)
zproxy_backend_state_purge(backend_state);
}
}
@ -285,29 +442,23 @@ static void zproxy_state_cfg_proxy_update(const struct zproxy_proxy_cfg *proxy,
struct zproxy_http_state *http_state)
{
const struct zproxy_service_cfg *service;
auto service_state = http_state->services.begin();
int found;
struct zproxy_service_state *service_state, *next;
bool found;
while (service_state != http_state->services.end()) {
found = 0;
list_for_each_entry_safe(service_state, next, &http_state->services,
list) {
found = false;
list_for_each_entry(service, &proxy->service_list, list) {
if (strcmp(service->name, service_state->first.c_str()) == 0) {
found = 1;
if (strcmp(service->name, service_state->name) == 0) {
found = true;
break;
}
}
if (!found) {
auto iter = service_state;
service_state++;
zproxy_sessions_free(iter->second->sessions);
http_state->services.erase(iter);
continue;
}
zproxy_state_cfg_service_update(service,
service_state->second.get());
service_state++;
if (!found)
zproxy_service_state_purge(service_state);
else
zproxy_state_cfg_service_update(service, service_state);
}
}
@ -327,77 +478,23 @@ void zproxy_state_cfg_update(struct zproxy_cfg *cfg)
}
}
if (!found) {
list_del(&http_state->list);
if (--http_state->refcnt == 0)
delete http_state;
continue;
}
zproxy_state_cfg_proxy_update(proxy, http_state);
if (!found)
zproxy_proxy_state_purge(http_state);
else
zproxy_state_cfg_proxy_update(proxy, http_state);
}
pthread_mutex_unlock(&list_mutex);
}
void zproxy_backend_state_purge(struct std::shared_ptr<zproxy_service_state> services)
struct zproxy_sessions *
zproxy_state_get_service_sessions(const char *service_name,
const struct list_head *service_list)
{
for (auto & backend_pair : services->backends) {
if (--backend_pair.second->refcnt == 0)
services->backends.erase(backend_pair.first);
struct zproxy_service_state *service_state;
list_for_each_entry(service_state, service_list, list) {
if (strcmp(service_state->name, service_name) == 0)
return service_state->sessions;
}
}
void zproxy_state_purge(struct zproxy_proxy_cfg *proxy)
{
struct zproxy_http_state *state_ptr, *next;
pthread_mutex_lock(&list_mutex);
list_for_each_entry_safe(state_ptr, next, &state_list, list) {
if (proxy->id != state_ptr->proxy_id)
continue;
if (--state_ptr->refcnt == 0) {
for (auto &service_pair : state_ptr->services)
zproxy_sessions_free(service_pair.second->sessions);
ev_timer_stop(zproxy_main.loop, &state_ptr->timer);
list_del(&state_ptr->list);
delete state_ptr;
continue;
}
}
pthread_mutex_unlock(&list_mutex);
}
struct zproxy_http_state *zproxy_state_lookup(uint32_t proxy_id)
{
struct zproxy_http_state *state;
pthread_mutex_lock(&list_mutex);
list_for_each_entry(state, &state_list, list) {
if(state->proxy_id == proxy_id) {
state->refcnt++;
return state;
}
}
pthread_mutex_unlock(&list_mutex);
return NULL;
}
void zproxy_state_release(struct zproxy_http_state **http_state)
{
(*http_state)->refcnt--;
*http_state = NULL;
pthread_mutex_unlock(&list_mutex);
}
struct zproxy_sessions *zproxy_state_get_session(const std::string &service,
std::unordered_map<std::string, std::shared_ptr<zproxy_service_state>> *service_list)
{
auto session_pair = service_list->find(service);
if (session_pair == service_list->end())
return NULL;
return session_pair->second->sessions;
}

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 1,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -13,7 +13,7 @@
{
"backends": [
{
"2xx-code-hits": 1,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 1,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 1,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 1,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 1,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -13,7 +13,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 1,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -2,7 +2,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,

View File

@ -13,7 +13,7 @@
{
"backends": [
{
"2xx-code-hits": 0,
"2xx-code-hits": 2,
"3xx-code-hits": 0,
"4xx-code-hits": 0,
"5xx-code-hits": 0,