proxy.h C 789 lines View on github.com → Search inside
1#ifndef PROXY_H2#define PROXY_H34#include "memcached.h"5#include "extstore.h"6#include <string.h>7#include <stdlib.h>8#include <ctype.h>9#include <errno.h>1011#include <lua.h>12#include <lualib.h>13#include <lauxlib.h>1415#include "config.h"1617#if defined(__linux__)18#define USE_EVENTFD 119#include <sys/eventfd.h>20#endif2122#ifdef HAVE_LIBURING23#include <liburing.h>24#include <poll.h> // POLLOUT for liburing.25#define PRING_QUEUE_SQ_ENTRIES 204826#define PRING_QUEUE_CQ_ENTRIES 1638427#endif2829#include "vendor/mcmc/mcmc.h"30#include "proto_proxy.h"31#include "proto_text.h"32#include "proto_parser.h"33#include "queue.h"34#define XXH_INLINE_ALL // modifier for xxh3's include below35#include "xxhash.h"3637#ifdef PROXY_DEBUG38#define P_DEBUG(...) \39    do { \40        fprintf(stderr, __VA_ARGS__); \41    } while (0)42#else43#define P_DEBUG(...)44#endif4546#define WSTAT_L(t) pthread_mutex_lock(&t->stats.mutex);47#define WSTAT_UL(t) pthread_mutex_unlock(&t->stats.mutex);48#define WSTAT_INCR(t, stat, amount) { \49    pthread_mutex_lock(&t->stats.mutex); \50    t->stats.stat += amount; \51    pthread_mutex_unlock(&t->stats.mutex); \52}53#define WSTAT_DECR(t, stat, amount) { \54    pthread_mutex_lock(&t->stats.mutex); \55    t->stats.stat -= amount; \56    pthread_mutex_unlock(&t->stats.mutex); \57}58#define STAT_L(ctx) pthread_mutex_lock(&ctx->stats_lock);59#define STAT_UL(ctx) pthread_mutex_unlock(&ctx->stats_lock);60#define STAT_INCR(ctx, stat, amount) { \61        pthread_mutex_lock(&ctx->stats_lock); \62        ctx->global_stats.stat += amount; \63        pthread_mutex_unlock(&ctx->stats_lock); \64}6566#define STAT_DECR(ctx, stat, amount) { \67        pthread_mutex_lock(&ctx->stats_lock); \68        ctx->global_stats.stat -= amount; \69        pthread_mutex_unlock(&ctx->stats_lock); \70}7172enum mcp_memprofile_types {73    mcp_memp_free = 0,74    mcp_memp_string,75    mcp_memp_table,76    mcp_memp_func,77    mcp_memp_userdata,78    mcp_memp_thread,79    mcp_memp_default,80    mcp_memp_realloc,81};8283struct mcp_memprofile {84    struct timespec last_status; // for per-second prints on status85    int id;86    uint64_t allocs[8];87    uint64_t alloc_bytes[8];88};8990// for various time conversion functions91#define NANOSECONDS(x) ((x) * 1E9 + 0.5)92#define MICROSECONDS(x) ((x) * 1E6 + 0.5)9394// Note: value created from thin air. Could be shorter.95#define MCP_REQUEST_MAXLEN KEY_MAX_LENGTH * 29697#define ENDSTR "END\r\n"98#define ENDLEN (sizeof(ENDSTR)-1)99100#define MCP_BACKEND_UPVALUE 1101102#define MCP_YIELD_INTERNAL 1103#define MCP_YIELD_WAITCOND 2104#define MCP_YIELD_WAITHANDLE 3105#define MCP_YIELD_SLEEP 4106107#define SHAREDVM_FGEN_IDX 1108#define SHAREDVM_FGENSLOT_IDX 2109#define SHAREDVM_BACKEND_IDX 3110111#define P_OK 0112113typedef struct _io_pending_proxy_t io_pending_proxy_t;114typedef struct proxy_event_thread_s proxy_event_thread_t;115116#ifdef HAVE_LIBURING117// TODO: pass in cqe->res instead of cqe?118typedef void (*proxy_event_cb)(void *udata, struct io_uring_cqe *cqe);119typedef struct {120    void *udata;121    proxy_event_cb cb;122    bool set; // NOTE: not sure if necessary if code structured properly123} proxy_event_t;124125void *proxy_event_thread_ur(void *arg);126#endif127128// Note: This ends up wasting a few counters, but simplifies the rest of the129// process for handling internal worker stats.130struct proxy_int_stats {131    uint64_t vm_gc_runs;132    uint64_t vm_memory_kb;133    uint64_t counters[CMD_FINAL];134};135136struct proxy_user_stats {137    int num_stats; // number of stats, for sizing various arrays138    uint64_t *counters; // array of counters.139};140141struct proxy_user_stats_entry {142    char *name;143    unsigned int cname; // offset into compact name buffer144    bool reset; // counter must reset this cycle145};146147struct proxy_global_stats {148    uint64_t config_reloads;149    uint64_t config_reload_fails;150    uint64_t config_cron_runs;151    uint64_t config_cron_fails;152    uint64_t backend_total;153    uint64_t backend_marked_bad; // backend set to autofail154    uint64_t backend_failed; // an error caused a backend reset155    uint64_t request_failed_depth; // requests fast-failed due to be depth156};157158struct proxy_tunables {159    struct timeval connect;160    struct timeval retry; // wait time before retrying a dead backend161    struct timeval read;162    struct timeval flap; // need to stay connected this long or it's flapping163    float flap_backoff_ramp; // factorial for retry time164    float gc_ratio; // how much lua VM growth to allow before running GC165    uint32_t flap_backoff_max; // don't backoff longer than this.166    int backend_depth_limit; // requests fast fail once depth over this limit167    int backend_failure_limit;168    int max_ustats; // limit the ustats index.169    bool tcp_keepalive;170    bool use_iothread; // default for using the bg io thread.171    bool use_tls; // whether or not be should use TLS172    bool down; // backend is forced into a down/bad state.173};174175struct proxy_logging {176    unsigned int deadline; // log if slower than N us (user specifies ms)177    unsigned int rate; // sampling178    bool all_errors; // always log on an error case179    char *detail;180};181182typedef STAILQ_HEAD(globalobj_head_s, mcp_globalobj_s) globalobj_head_t;183typedef struct {184    lua_State *proxy_state; // main configuration vm185    proxy_event_thread_t *proxy_io_thread;186    int64_t active_req_limit; // max total in-flight requests187    uint64_t buffer_memory_limit; // max bytes for send/receive buffers.188#ifdef PROXY_TLS189    void *tls_ctx;190#endif191    int user_stats_num; // highest seen stat index192    struct proxy_user_stats_entry *user_stats;193    char *user_stats_namebuf; // compact linear buffer for stat names194    struct proxy_tunables tunables; // NOTE: updates covered by stats_lock195    struct proxy_global_stats global_stats;196    // less frequently used entries down here.197    void *proxy_code;198    lua_State *proxy_sharedvm; // sub VM for short-lock global events/data199    pthread_mutex_t stats_lock; // used for rare global counters200    pthread_mutex_t config_lock;201    pthread_cond_t config_cond;202    pthread_t config_tid;203    pthread_mutex_t worker_lock;204    pthread_cond_t worker_cond;205    pthread_t manager_tid; // deallocation management thread206    pthread_mutex_t manager_lock;207    pthread_cond_t manager_cond;208    pthread_mutex_t sharedvm_lock; // protect statevm above209    globalobj_head_t manager_head; // stack for pool deallocation.210    int config_generation; // counter tracking config reloads211    int cron_ref; // reference to lua cron table212    int cron_next; // next cron to sleep to / execute213    bool worker_done; // signal variable for the worker lock/cond system.214    bool worker_failed; // covered by worker_lock as well.215    bool use_uring; // use IO_URING for backend connections.216    bool loading; // bool indicating an active config load.217    bool memprofile; // indicate if we want to profile lua memory.218    uint8_t memprofile_thread_counter;219} proxy_ctx_t;220221#define PROXY_GET_THR_CTX(L) ((*(LIBEVENT_THREAD **)lua_getextraspace(L))->proxy_ctx)222#define PROXY_GET_THR(L) (*(LIBEVENT_THREAD **)lua_getextraspace(L))223// Operations from the config VM don't have a libevent thread.224#define PROXY_GET_CTX(L) (*(proxy_ctx_t **)lua_getextraspace(L))225226struct proxy_hook_ref {227    int lua_ref;228    void *ctx; // if we're a generator based function.229};230231struct proxy_hook_tagged {232    uint64_t tag;233    struct proxy_hook_ref ref;234};235236struct proxy_hook {237    struct proxy_hook_ref ref;238    int tagcount;239    struct proxy_hook_tagged *tagged; // array of possible tagged hooks.240};241242// TODO (v2): some hash functions (crc?) might require initializers. If we run into243// any the interface might need expanding.244typedef uint64_t (*key_hash_func)(const void *key, size_t len, uint64_t seed);245struct proxy_hash_func {246    key_hash_func func;247};248typedef const char *(*key_hash_filter_func)(const char *conf, const char *key, size_t klen, size_t *newlen);249typedef uint32_t (*hash_selector_func)(uint64_t hash, void *ctx);250struct proxy_hash_caller {251    hash_selector_func selector_func;252    void *ctx;253};254255enum mcp_backend_states {256    mcp_backend_read = 0, // waiting to read any response257    mcp_backend_parse, // have some buffered data to check258    mcp_backend_read_end, // looking for an "END" marker for GET259    mcp_backend_want_read, // read more data to complete command260    mcp_backend_next, // advance to the next IO261    mcp_backend_next_close, // complete current request, then close socket262};263264typedef struct mcp_cron_s mcp_cron_t;265typedef struct mcp_backend_wrap_s mcp_backend_wrap_t;266typedef struct mcp_backend_label_s mcp_backend_label_t;267typedef struct mcp_backend_s mcp_backend_t;268typedef struct mcp_request_s mcp_request_t;269typedef struct mcp_rcontext_s mcp_rcontext_t;270typedef struct mcp_funcgen_s mcp_funcgen_t;271272#define PARSER_MAX_TOKENS 24273274#define MAX_REQ_TOKENS 2275struct mcp_request_s {276    mcp_parser_t pr; // non-lua-specific parser handling.277    char request[];278};279280struct mcp_cron_s {281    uint32_t gen;282    uint32_t next;283    uint32_t every;284    bool repeat;285};286287#define MAX_LABELLEN 512288#define MAX_NAMELEN 255289#define MAX_PORTLEN 6290// TODO (v2): IOV_MAX tends to be 1000+ which would allow for more batching but we291// don't have a good temporary space and don't want to malloc/free on every292// write. transmit() uses the stack but we can't do that for uring's use case.293#if MEMCACHED_DEBUG294#define BE_IOV_MAX 128 // let bench tests trigger max condition easily295#elif (IOV_MAX > 1024)296#define BE_IOV_MAX 1024297#else298#define BE_IOV_MAX IOV_MAX299#endif300// lua descriptor object: passed to pools, which create wrappers.301struct mcp_backend_label_s {302    char name[MAX_NAMELEN+1];303    char port[MAX_PORTLEN+1];304    char label[MAX_LABELLEN+1];305    size_t llen; // cache label length for small speedup in pool creation.306    int conncount; // number of sockets to make.307    bool use_logging;308    struct proxy_tunables tunables;309    struct proxy_logging logging;310};311312// lua object wrapper meant to own a malloc'ed conn structure313// when this object is created, it ships its connection to the real owner314// (worker, IO thread, etc)315// when this object is garbage collected, it ships a notice to the owner316// thread to stop using and free the backend conn memory.317struct mcp_backend_wrap_s {318    mcp_backend_t *be;319};320321struct mcp_backendconn_s {322    mcp_backend_t *be_parent; // find the wrapper.323    int self; // our index into the parent array.324    int depth; // total number of requests in queue325    int pending_read; // number of requests written to socket, pending read.326    int failed_count; // number of fails (timeouts) in a row327    int flap_count; // number of times we've "flapped" into bad state.328    proxy_event_thread_t *event_thread; // event thread owning this backend.329    void *client; // mcmc client330#ifdef PROXY_TLS331    void *ssl;332#endif333    iop_head_t iop_write; // requests needing to be written334    iop_head_t iop_read; // requests waiting for read response335    char *rbuf; // statically allocated read buffer.336    size_t rbufused; // currently active bytes in the buffer337    struct event main_event; // libevent: changes role, mostly for main read events338    struct event write_event; // libevent: only used when socket wbuf full339    struct event timeout_event; // libevent: alarm for pending reads340    struct proxy_tunables tunables;341    struct timeval last_failed; // time the backend was last reset.342    enum mcp_backend_states state; // readback state machine343    int connect_flags; // flags to pass to mcmc_connect344    bool connecting; // in the process of an asynch connection.345    bool validating; // in process of validating a new backend connection.346    bool can_write; // recently got a WANT_WRITE or are connecting.347    bool bad; // timed out, marked as bad.348#ifndef PROXY_TLS349    bool ssl;350#endif351    struct iovec write_iovs[BE_IOV_MAX]; // iovs to stage batched writes352};353354// TODO: move depth and flags to a second top level array so we can make index355// decisions from fewer memory stalls.356struct mcp_backend_s {357    int conncount; // total number of connections managed.358    int depth; // temporary depth counter for io_head359    bool transferred; // if beconn has been shipped to owner thread.360    bool use_io_thread; // note if this backend is worker-local or not.361    bool stacked; // if backend already queued for syscalls.362    bool use_logging; // if automatic logging is enabled.363    STAILQ_ENTRY(mcp_backend_s) beconn_next; // stack for connecting conns364    STAILQ_ENTRY(mcp_backend_s) be_next; // stack for backends365    iop_head_t iop_head; // stack of inbound requests.366    struct proxy_logging logging;367    struct proxy_tunables tunables; // this gets copied a few times for speed.368    char name[MAX_NAMELEN+1];369    char port[MAX_PORTLEN+1];370    char label[MAX_LABELLEN+1];371    struct mcp_backendconn_s be[];372};373typedef STAILQ_HEAD(be_head_s, mcp_backend_s) be_head_t;374typedef STAILQ_HEAD(beconn_head_s, mcp_backend_s) beconn_head_t;375376struct proxy_event_thread_s {377    pthread_t thread_id;378    struct event_base *base;379    struct event notify_event; // listen event for the notify pipe/eventfd.380    struct event beconn_event; // listener for backends in connect state381#ifdef HAVE_LIBURING382    struct io_uring ring;383    proxy_event_t ur_notify_event; // listen on eventfd.384    proxy_event_t ur_benotify_event; // listen on eventfd for backend connections.385    eventfd_t event_counter;386    eventfd_t beevent_counter;387    bool use_uring;388#endif389#ifdef PROXY_TLS390    char *tls_wbuf;391    size_t tls_wbuf_size;392#endif393    pthread_mutex_t mutex; // covers stack.394    pthread_cond_t cond; // condition to wait on while stack drains.395    iop_head_t iop_head_in; // inbound requests to process.396    be_head_t be_head; // stack of backends for processing.397    beconn_head_t beconn_head_in; // stack of backends for connection processing.398#ifdef USE_EVENTFD399    int event_fd; // for request ingestion400    int be_event_fd; // for backend ingestion401#else402    int notify_receive_fd;403    int notify_send_fd;404    int be_notify_receive_fd;405    int be_notify_send_fd;406#endif407    proxy_ctx_t *ctx; // main context.408};409410#define RESP_CMD_MAX 8411typedef struct {412    mcmc_resp_t resp;413    mcmc_tokenizer_t tok; // optional tokenization of res414    char *buf; // response line + potentially value.415    mc_resp *cresp; // client mc_resp object during extstore fetches.416    LIBEVENT_THREAD *thread; // cresp's owner thread needed for extstore cleanup.417    mcp_backend_t *be; // backend that generated this response418    unsigned int blen; // total size of the value to read.419    struct timeval start; // time this object was created.420    long elapsed; // time elapsed once handled.421    int status; // status code from mcmc_read()422    int bread; // amount of bytes read into value so far.423    uint8_t cmd; // from parser (pr.command)424} mcp_resp_t;425426// re-cast an io_pending_t into this more descriptive structure.427// the first few items _must_ match the original struct.428struct _io_pending_proxy_t {429    uint8_t io_queue_type;430    uint8_t io_sub_type;431    uint8_t payload; // payload offset432    LIBEVENT_THREAD *thread;433    conn *c;434    mc_resp *resp;435    io_queue_cb return_cb; // called on worker thread.436    io_queue_cb finalize_cb; // called back on the worker thread.437    STAILQ_ENTRY(io_pending_t) iop_next; // queue chain.438    // original struct ends here439440    mcp_rcontext_t *rctx; // pointer to request context.441    mcp_resp_t *client_resp; // reference (currently pointing to a lua object)442    int queue_handle; // queue slot to return this result to443    union {444        // extstore IO.445        struct {446            obj_io eio;447            item *hdr_it;448            mc_resp *tresp; // temporary mc_resp for storage to fill.449            int gettype;450            int iovec_data;451            bool miss;452            bool badcrc;453            bool active;454        };455        // backend request IO456        struct {457            mcp_backend_t *backend; // backend server to request from458            struct iovec iov[2]; // request string + tail buffer459            int iovcnt; // 1 or 2...460            unsigned int iovbytes; // total bytes in the iovec461            bool flushed; // whether we've fully written this request to a backend.462            bool background; // dummy IO for backgrounded awaits463        };464    };465};466467struct mcp_globalobj_s {468    pthread_mutex_t lock; // protects refcount/object.469    STAILQ_ENTRY(mcp_globalobj_s) next;470    int refcount;471    int self_ref;472};473474// Note: does *be have to be a sub-struct? how stable are userdata pointers?475// https://stackoverflow.com/questions/38718475/lifetime-of-lua-userdata-pointers476// - says no.477typedef struct {478    int ref; // luaL_ref reference of backend_wrap_t obj.479    mcp_backend_t *be;480} mcp_pool_be_t;481482#define KEY_HASH_FILTER_MAX 5483typedef struct mcp_pool_s mcp_pool_t;484struct mcp_pool_s {485    struct proxy_hash_caller phc;486    key_hash_filter_func key_filter;487    key_hash_func key_hasher;488    proxy_ctx_t *ctx; // main context.489    char key_filter_conf[KEY_HASH_FILTER_MAX+1];490    struct mcp_globalobj_s g;491    char beprefix[MAX_LABELLEN+1]; // TODO: should probably be shorter.492    uint64_t hash_seed; // calculated from a string.493    int pool_size;494    int pool_be_total; // can be different from pool size for worker IO495    int phc_ref;496    bool use_iothread;497    mcp_pool_be_t pool[];498};499500typedef struct {501    mcp_pool_t *main; // ptr to original502    mcp_pool_be_t *pool; // ptr to main->pool starting offset for owner thread.503} mcp_pool_proxy_t;504505// utils506bool proxy_bufmem_checkadd(LIBEVENT_THREAD *t, int len);507void mcp_sharedvm_delta(proxy_ctx_t *ctx, int tidx, const char *name, int delta);508void mcp_sharedvm_remove(proxy_ctx_t *ctx, int tidx, const char *name);509510void mcp_gobj_ref(lua_State *L, struct mcp_globalobj_s *g);511void mcp_gobj_unref(proxy_ctx_t *ctx, struct mcp_globalobj_s *g);512void mcp_gobj_finalize(struct mcp_globalobj_s *g);513514// networking interface515void proxy_init_event_thread(proxy_event_thread_t *t, proxy_ctx_t *ctx, struct event_base *base);516void *proxy_event_thread(void *arg);517void proxy_run_backend_queue(be_head_t *head);518struct mcp_backendconn_s *proxy_choose_beconn(mcp_backend_t *be);519mcp_resp_t *mcp_prep_bare_resobj(lua_State *L, LIBEVENT_THREAD *t);520void mcp_resp_set_elapsed(mcp_resp_t *r);521io_pending_proxy_t *mcp_queue_rctx_io(mcp_rcontext_t *rctx, mcp_request_t *rq, mcp_backend_t *be, mcp_resp_t *r);522523// internal request interface524int mcplib_internal(lua_State *L);525int mcplib_internal_run(mcp_rcontext_t *rctx);526void *mcp_rcontext_internal(mcp_rcontext_t *rctx, mcp_request_t *rq, mcp_resp_t *r);527528// user stats interface529#define MAX_USTATS_DEFAULT 1024530int mcplib_add_stat(lua_State *L);531int mcplib_stat(lua_State *L);532size_t _process_request_next_key(mcp_parser_t *pr);533mcp_request_t *mcp_new_request(lua_State *L, mcp_parser_t *pr, const char *command, size_t cmdlen);534void mcp_set_request(mcp_parser_t *pr, mcp_request_t *r, const char *command, size_t cmdlen);535536// rate limit interfaces537int mcplib_ratelim_tbf(lua_State *L);538int mcplib_ratelim_tbf_call(lua_State *L);539int mcplib_ratelim_global_tbf(lua_State *L);540int mcplib_ratelim_proxy_tbf_call(lua_State *L);541int mcp_ratelim_proxy_tbf(lua_State *from, lua_State *to);542int mcplib_ratelim_global_tbf_gc(lua_State *L);543int mcplib_ratelim_proxy_tbf_gc(lua_State *L);544545// request function generator interface546void proxy_return_rctx_cb(io_pending_t *pending);547void proxy_finalize_rctx_cb(io_pending_t *pending);548549enum mcp_rqueue_e {550    QWAIT_IDLE = 0,551    QWAIT_ANY,552    QWAIT_OK,553    QWAIT_GOOD,554    QWAIT_FASTGOOD,555    QWAIT_HANDLE,556    QWAIT_SLEEP,557};558559#define FGEN_NAME_MAXLEN 80560struct mcp_funcgen_s {561    LIBEVENT_THREAD *thread; // worker thread that created this funcgen.562    int generator_ref; // reference to the generator function.563    int self_ref; // self-reference if we're attached anywhere564    int argument_ref; // reference to an argument to pass to generator565    int max_queues; // how many queue slots rctx's have566    int uobj_queues; // how many extra queue slots for object storage we have567    unsigned int refcount; // reference counter568    unsigned int total; // total contexts managed569    unsigned int free; // free contexts570    unsigned int free_max; // size of list below.571    unsigned int free_pressure; // "pressure" for when to early release rctx572    bool closed; // the hook holding this fgen has been replaced573    bool ready; // if we're locked down or not.574    bool is_router; // if this fgen is actually a router object.575    struct timespec free_waiter; // must be "too free" for this much time576    mcp_rcontext_t **list;577    struct mcp_rqueue_s *queue_list;578    char name[FGEN_NAME_MAXLEN+1]; // string name for the generator.579};580581enum mcp_funcgen_router_e {582    FGEN_ROUTER_NONE = 0,583    FGEN_ROUTER_CMDMAP,584    FGEN_ROUTER_SHORTSEP,585    FGEN_ROUTER_LONGSEP,586    FGEN_ROUTER_ANCHORSM,587    FGEN_ROUTER_ANCHORBIG,588};589590struct mcp_router_long_s {591    char start[KEY_HASH_FILTER_MAX+1];592    char stop[KEY_HASH_FILTER_MAX+1];593};594595// To simplify the attach/start code we wrap a funcgen with the router596// structure. This allows us to have a larger router structure without597// bloating the fgen object itself, and still benefit from letting funcgen598// new/cleanup handle most of the memory management.599struct mcp_funcgen_router {600    mcp_funcgen_t fgen_self;601    enum mcp_funcgen_router_e type;602    union {603        char sep;604        char lsep[KEY_HASH_FILTER_MAX+1];605        char anchorsm[2]; // short anchored mode.606        struct mcp_router_long_s big;607    } conf;608    int map_ref;609    mcp_funcgen_t *def_fgen; // default route610    mcp_funcgen_t *cmap[CMD_END_STORAGE]; // fallback command map611};612613#define RQUEUE_TYPE_NONE 0614#define RQUEUE_TYPE_POOL 1615#define RQUEUE_TYPE_INT  2616#define RQUEUE_TYPE_FGEN 3617#define RQUEUE_TYPE_UOBJ 4 // user tracked object types past this point618#define RQUEUE_TYPE_UOBJ_REQ 5619#define RQUEUE_TYPE_UOBJ_RES 6620#define RQUEUE_ASSIGNED (1<<0)621#define RQUEUE_R_RESUME (1<<1)622#define RQUEUE_R_GOOD (1<<3)623#define RQUEUE_R_OK (1<<4)624#define RQUEUE_R_ANY (1<<5)625#define RQUEUE_R_ERROR (1<<7)626#define RQUEUE_UOBJ_MAX UINT8_MAX627628enum mcp_rqueue_state {629    RQUEUE_IDLE = 0,630    RQUEUE_QUEUED,631    RQUEUE_ACTIVE,632    RQUEUE_COMPLETE,633    RQUEUE_WAITED634};635636struct mcp_rqueue_s {637    int obj_ref; // reference to pool/func/etc object638    int cb_ref; // if a lua callback was specified639    int req_ref; // reference to associated request object.640    int res_ref; // reference to lua response object.641    void *obj; // direct pointer to the object for fast access.642    mcp_request_t *rq; // request set to this slot643    mcp_resp_t *res_obj; // pointer to result object644    enum mcp_rqueue_state state; // queued/active/etc645    uint8_t obj_type; // what the obj_ref actually is.646    uint8_t flags; // bit flags for various states647};648649struct mcp_rcontext_s {650    int self_ref; // reference to our own object651    int request_ref; // top level request for this context.652    int function_ref; // ref to the created route function.653    int coroutine_ref; // ref to our encompassing coroutine.654    int pending_reqs; // pending requests and sub-requests655    unsigned int wait_count;656    unsigned int wait_done; // TODO: change these variables to uint8's657    int wait_handle; // waiting on a specific queue slot658    int parent_handle; // queue slot in parent rctx659    int conn_fd; // fd of the originating client, as *c can become invalid660    enum mcp_rqueue_e wait_mode;661    uint8_t lua_narg; // number of responses to push when yield resuming.662    uint8_t uobj_count; // number of extra tracked req/res objects.663    bool ascii_multiget; // ascii multiget mode. (hide errors/END)664    lua_State *Lc; // coroutine thread pointer.665    mcp_request_t *request; // ptr to the above reference.666    mcp_rcontext_t *parent; // parent rctx in the call graph667    conn *c; // associated client object.668    mc_resp *resp; // top level response object to fill.669    mcp_funcgen_t *fgen; // parent function generator context.670    struct event timeout_event; // for *_wait_timeout() and sleep() calls671    struct mcp_rqueue_s qslots[]; // queueable slots.672};673674#define mcp_is_flag_invalid(f) (f < 65 || f > 122)675676void mcp_run_rcontext_handle(mcp_rcontext_t *rctx, int handle);677void mcp_process_rctx_wait(mcp_rcontext_t *rctx, int handle);678int mcp_process_rqueue_return(mcp_rcontext_t *rctx, int handle, mcp_resp_t *res);679int mcplib_rcontext_handle_set_cb(lua_State *L);680int mcplib_rcontext_enqueue(lua_State *L);681int mcplib_rcontext_wait_cond(lua_State *L);682int mcplib_rcontext_wait_handle(lua_State *L);683int mcplib_rcontext_enqueue_and_wait(lua_State *L);684int mcplib_rcontext_res_good(lua_State *L);685int mcplib_rcontext_res_any(lua_State *L);686int mcplib_rcontext_res_ok(lua_State *L);687int mcplib_rcontext_result(lua_State *L);688int mcplib_rcontext_best_result(lua_State *L);689int mcplib_rcontext_worst_result(lua_State *L);690int mcplib_rcontext_cfd(lua_State *L);691int mcplib_rcontext_tls_peer_cn(lua_State *L);692int mcplib_rcontext_request_new(lua_State *L);693int mcplib_rcontext_response_new(lua_State *L);694int mcplib_rcontext_sleep(lua_State *L);695int mcplib_funcgenbare_new(lua_State *L);696int mcplib_funcgen_new(lua_State *L);697int mcplib_funcgen_new_handle(lua_State *L);698int mcplib_funcgen_ready(lua_State *L);699int mcplib_router_new(lua_State *L);700mcp_rcontext_t *mcp_funcgen_start(lua_State *L, mcp_funcgen_t *fgen, mcp_parser_t *pr);701mcp_rcontext_t *mcp_funcgen_get_rctx(lua_State *L, int fgen_ref, mcp_funcgen_t *fgen);702void mcp_funcgen_return_rctx(mcp_rcontext_t *rctx);703int mcplib_funcgen_gc(lua_State *L);704void mcp_funcgen_reference(lua_State *L);705void mcp_funcgen_dereference(lua_State *L, mcp_funcgen_t *fgen);706void mcp_rcontext_push_rqu_res(lua_State *L, mcp_rcontext_t *rctx, int handle);707void mcplib_rqu_log(mcp_request_t *rq, mcp_resp_t *rs, int flag, int cfd);708709int mcplib_factory_command_new(lua_State *L);710711// request interface712int mcplib_request(lua_State *L);713int mcplib_request_command(lua_State *L);714int mcplib_request_key(lua_State *L);715int mcplib_request_ltrimkey(lua_State *L);716int mcplib_request_rtrimkey(lua_State *L);717int mcplib_request_raw_line(lua_State *L);718int mcplib_request_raw_value(lua_State *L);719int mcplib_request_token(lua_State *L);720int mcplib_request_token_int(lua_State *L);721int mcplib_request_ntokens(lua_State *L);722int mcplib_request_has_flag(lua_State *L);723int mcplib_request_flag_token(lua_State *L);724int mcplib_request_flag_token_int(lua_State *L);725int mcplib_request_flag_add(lua_State *L);726int mcplib_request_flag_set(lua_State *L);727int mcplib_request_flag_replace(lua_State *L);728int mcplib_request_flag_del(lua_State *L);729int mcplib_request_gc(lua_State *L);730int mcplib_request_match_res(lua_State *L);731void mcp_request_cleanup(LIBEVENT_THREAD *t, mcp_request_t *rq);732733// response interface734int mcplib_response_elapsed(lua_State *L);735int mcplib_response_ok(lua_State *L);736int mcplib_response_hit(lua_State *L);737int mcplib_response_vlen(lua_State *L);738int mcplib_response_code(lua_State *L);739int mcplib_response_line(lua_State *L);740int mcplib_response_flag_blank(lua_State *L);741int mcplib_response_raw_string(lua_State *L);742743// inspector interface744int mcplib_req_inspector_new(lua_State *L);745int mcplib_res_inspector_new(lua_State *L);746int mcplib_inspector_gc(lua_State *L);747int mcplib_inspector_call(lua_State *L);748749// mutator interface750int mcplib_req_mutator_new(lua_State *L);751int mcplib_res_mutator_new(lua_State *L);752int mcplib_mutator_gc(lua_State *L);753int mcplib_mutator_call(lua_State *L);754755void mcp_response_cleanup(LIBEVENT_THREAD *t, mcp_resp_t *r);756void mcp_set_resobj(mcp_resp_t *r, mcp_request_t *rq, mcp_backend_t *be, LIBEVENT_THREAD *t);757int mcplib_response_gc(lua_State *L);758int mcplib_response_close(lua_State *L);759760int mcplib_open_dist_jump_hash(lua_State *L);761int mcplib_open_dist_ring_hash(lua_State *L);762763int proxy_run_rcontext(mcp_rcontext_t *rctx);764mcp_backend_t *mcplib_pool_proxy_call_helper(mcp_pool_proxy_t *pp, const char *key, size_t len);765void mcp_request_attach(mcp_request_t *rq, io_pending_proxy_t *p);766int mcp_request_render(mcp_request_t *rq, int idx, char flag, const char *tok, size_t len);767int mcp_request_append(mcp_request_t *rq, const char flag, const char *tok, size_t len);768void proxy_lua_error(lua_State *L, const char *s);769#define proxy_lua_ferror(L, fmt, ...) \770    do { \771        lua_pushfstring(L, fmt, __VA_ARGS__); \772        lua_error(L); \773    } while (0)774775#define PROXY_SERVER_ERROR "SERVER_ERROR "776#define PROXY_CLIENT_ERROR "CLIENT_ERROR "777void proxy_out_errstring(mc_resp *resp, char *type, const char *str);778int _start_proxy_config_threads(proxy_ctx_t *ctx);779int proxy_thread_loadconf(proxy_ctx_t *ctx, LIBEVENT_THREAD *thr);780781// TODO (v2): more .h files, perhaps?782int mcplib_open_hash_xxhash(lua_State *L);783784__attribute__((unused)) void dump_stack(lua_State *L, const char *msg);785__attribute__((unused)) void dump_registry(lua_State *L, const char *msg);786__attribute__((unused)) void dump_funcgen(lua_State *L, const char *name, const char *msg);787__attribute__((unused)) void dump_pools(lua_State *L, const char *msg);788#endif

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings