]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] added the necessary infrastructure to support per-server session limits...
authorwilly tarreau <willy@wtap.(none)>
Wed, 12 Apr 2006 17:26:23 +0000 (19:26 +0200)
committerwilly tarreau <willy@wtap.(none)>
Sat, 15 Apr 2006 20:59:34 +0000 (22:59 +0200)
haproxy.c

index a87b341866c37ea3597ddb963956be85aa72292b..d4953ac4f3480fa61f2ad7a345bc61884e3c6ae5 100644 (file)
--- a/haproxy.c
+++ b/haproxy.c
@@ -86,6 +86,7 @@
 #endif
 
 #include "include/appsession.h"
+#include "include/mini-clist.h"
 
 #ifndef HAPROXY_VERSION
 #define HAPROXY_VERSION "1.2.12"
@@ -283,6 +284,7 @@ int strlcpy2(char *dst, const char *src, int size) {
 
 #define sizeof_task    sizeof(struct task)
 #define sizeof_session sizeof(struct session)
+#define sizeof_pendconn        sizeof(struct pendconn)
 #define sizeof_buffer  sizeof(struct buffer)
 #define sizeof_fdtab   sizeof(struct fdtab)
 #define sizeof_requri  REQURI_LEN
@@ -406,12 +408,13 @@ int strlcpy2(char *dst, const char *src, int size) {
 
 /* different possible states for the server side */
 #define SV_STIDLE      0
-#define SV_STCONN      1
-#define SV_STHEADERS   2
-#define SV_STDATA      3
-#define SV_STSHUTR     4
-#define SV_STSHUTW     5
-#define SV_STCLOSE     6
+#define SV_STCPEND     1
+#define SV_STCONN      2
+#define SV_STHEADERS   3
+#define SV_STDATA      4
+#define SV_STSHUTR     5
+#define SV_STSHUTW     6
+#define SV_STCLOSE     7
 
 /* result of an I/O event */
 #define        RES_SILENT      0       /* didn't happen */
@@ -497,12 +500,20 @@ struct buffer {
     char data[BUFSIZE];
 };
 
+struct pendconn {
+    struct list list;                  /* chaining ... */
+    struct session *sess;              /* the session waiting for a connection */
+    struct server *srv;                        /* the server we are waiting for */
+};
+
 struct server {
     struct server *next;
     int state;                         /* server state (SRV_*) */
     int  cklen;                                /* the len of the cookie, to speed up checks */
     char *cookie;                      /* the id set in the cookie */
     char *id;                          /* just for identification */
+    struct list pendconns;             /* pending connections */
+    int nbpend;                                /* number of pending connections */
     struct sockaddr_in addr;           /* the address to connect to */
     struct sockaddr_in source_addr;    /* the address to which we want to bind for connect() */
     short check_port;                  /* the port to use for the health checks */
@@ -515,6 +526,7 @@ struct server {
     unsigned int wscore;               /* weight score, used during srv map computation */
     int cur_sess;                      /* number of currently active sessions (including syn_sent) */
     unsigned int cum_sess;             /* cumulated number of sessions really sent to this server */
+    unsigned int maxconn;              /* max # of active sessions. 0 = unlimited. */
     struct proxy *proxy;               /* the proxy this server belongs to */
 };
 
@@ -551,6 +563,7 @@ struct session {
     struct sockaddr_storage cli_addr;  /* the client address */
     struct sockaddr_in srv_addr;       /* the address to connect to */
     struct server *srv;                        /* the server being used */
+    struct pendconn *pend_pos;         /* if not NULL, points to the position in the pending queue */
     char **req_cap;                    /* array of captured request headers (may be NULL) */
     char **rsp_cap;                    /* array of captured response headers (may be NULL) */
     struct {
@@ -690,6 +703,7 @@ fd_set      *StaticReadEvent,
 int cfg_polling_mechanism = 0;     /* POLL_USE_{SELECT|POLL|EPOLL} */
 
 void **pool_session = NULL,
+    **pool_pendconn = NULL,
     **pool_buffer   = NULL,
     **pool_fdtab    = NULL,
     **pool_requri   = NULL,
@@ -854,7 +868,7 @@ static int stats_tsk_lsrch, stats_tsk_rsrch,
 /*********************************************************************/
 #ifdef DEBUG_FULL
 static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
-static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
+static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
 #endif
 
 /*********************************************************************/
@@ -1754,6 +1768,65 @@ struct task *task_queue(struct task *task) {
 }
 
 
+/*********************************************************************/
+/*   pending connections queues **************************************/
+/*********************************************************************/
+
+/*
+ * returns the first pending connection of server <s> or NULL if none.
+ */
+static inline struct pendconn *pendconn_peek(struct server *s) {
+    if (!s->nbpend)
+       return NULL;
+
+    return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
+}
+
+/*
+ * Detaches pending connection <p>, decreases the pending count, and frees
+ * the pending connection.
+ */
+static inline void pendconn_free(struct pendconn *p) {
+    LIST_DEL(&p->list);
+    p->sess->pend_pos = NULL;
+    p->srv->nbpend--;
+    pool_free(pendconn, p);
+}
+
+/* detaches the first pending connection for server <s> and returns its
+ * associated session. If no pending connection is found, NULL is returned.
+ */
+static inline struct session *pendconn_get(struct server *s) {
+    struct pendconn *p;
+    struct session *sess;
+
+    p = pendconn_peek(s);
+    if (!p)
+       return NULL;
+    sess = p->sess;
+    pendconn_free(p);
+    return sess;
+}
+
+/* adds the session <sess> to the pending connection list of server <srv>.
+ * All counters and back pointers are updated accordingly. Returns NULL if
+ * no memory is available, otherwise the pendconn itself.
+ */
+static struct pendconn *pendconn_add(struct server *srv, struct session *sess) {
+    struct pendconn *p;
+
+    p = pool_alloc(pendconn);
+    if (!p)
+       return NULL;
+
+    LIST_ADDQ(&srv->pendconns, &p->list);
+    p->sess = sess;
+    p->srv  = srv;
+    sess->pend_pos = p;
+    srv->nbpend++;
+    return p;
+}
+
 /*********************************************************************/
 /*   more specific functions   ***************************************/
 /*********************************************************************/
@@ -1780,6 +1853,8 @@ static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
  * frees  the context associated to a session. It must have been removed first.
  */
 static inline void session_free(struct session *s) {
+    if (s->pend_pos)
+       pendconn_free(s->pend_pos);
     if (s->req)
        pool_free(buffer, s->req);
     if (s->rep)
@@ -7047,6 +7122,7 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
        curproxy->srv = newsrv;
        newsrv->proxy = curproxy;
 
+       LIST_INIT(&newsrv->pendconns);
        do_check = 0;
        newsrv->state = SRV_RUNNING; /* early server setup */
        newsrv->id = strdup(args[1]);
@@ -7118,6 +7194,10 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
                newsrv->uweight = w - 1;
                cur_arg += 2;
            }
+           else if (!strcmp(args[cur_arg], "maxconn")) {
+               newsrv->maxconn = atol(args[cur_arg + 1]);
+               cur_arg += 2;
+           }
            else if (!strcmp(args[cur_arg], "check")) {
                global.maxsock++;
                do_check = 1;
@@ -8914,3 +8994,10 @@ static int appsession_refresh(struct task *t) {
     return TBLCHKINT;
 } /* end appsession_refresh */
 
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ */