From 982b6e37e448d5620585a2dba292e6315a0742cb Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 25 Jan 2009 13:49:53 +0100 Subject: [PATCH] [MEDIUM] introduce pipe pools A new data type has been added : pipes. Some pre-allocated empty pipes are maintained in a pool for users such as splice which use them a lot for very short times. Pipes are allocated using get_pipe() and released using put_pipe(). Pipes which are released with pending data are immediately killed. The struct pipe is small (16 to 20 bytes) and may even be further reduced by unifying ->data and ->next. It would be nice to have a dedicated cleanup task which would watch for the pipes usage and destroy a few of them from time to time. --- Makefile | 2 +- Makefile.bsd | 2 +- Makefile.osx | 2 +- include/proto/pipe.h | 54 +++++++++++++++++++++ include/types/pipe.h | 45 ++++++++++++++++++ src/pipe.c | 109 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 include/proto/pipe.h create mode 100644 include/types/pipe.h create mode 100644 src/pipe.c diff --git a/Makefile b/Makefile index dc39ec478..89f1b61c6 100644 --- a/Makefile +++ b/Makefile @@ -449,7 +449,7 @@ endif OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \ src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \ - src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ + src/time.o src/fd.o src/pipe.o src/regex.o src/cfgparse.o src/server.o \ src/checks.o src/queue.o src/client.o src/proxy.o src/proto_uxst.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/stream_interface.o src/dumpstats.o src/proto_tcp.o \ diff --git a/Makefile.bsd b/Makefile.bsd index 0c385f17e..22dc3e778 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -100,7 +100,7 @@ LDFLAGS = -g OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \ src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \ - src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ + src/time.o src/fd.o src/pipe.o src/regex.o src/cfgparse.o src/server.o \ src/checks.o src/queue.o src/client.o src/proxy.o src/proto_uxst.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/stream_interface.o src/dumpstats.o src/proto_tcp.o \ diff --git a/Makefile.osx b/Makefile.osx index 64f25e9a2..cb4d4c886 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -97,7 +97,7 @@ LDFLAGS = -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386 -mma OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \ src/uri_auth.o src/standard.o src/buffers.o src/log.o src/task.o \ - src/time.o src/fd.o src/regex.o src/cfgparse.o src/server.o \ + src/time.o src/fd.o src/pipe.o src/regex.o src/cfgparse.o src/server.o \ src/checks.o src/queue.o src/client.o src/proxy.o src/proto_uxst.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/stream_interface.o src/dumpstats.o src/proto_tcp.o \ diff --git a/include/proto/pipe.h b/include/proto/pipe.h new file mode 100644 index 000000000..0c0216586 --- /dev/null +++ b/include/proto/pipe.h @@ -0,0 +1,54 @@ +/* + include/proto/pipe.h + Pipe management + + Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, version 2.1 + exclusively. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PROTO_PIPE_H +#define _PROTO_PIPE_H + +#include +#include + +extern int pipes_used; /* # of pipes in use (2 fds each) */ +extern int pipes_free; /* # of pipes unused (2 fds each) */ + +/* return a pre-allocated empty pipe. Try to allocate one if there isn't any + * left. NULL is returned if a pipe could not be allocated. + */ +struct pipe *get_pipe(); + +/* destroy a pipe, possibly because an error was encountered on it. Its FDs + * will be closed and it will not be reinjected into the live pool. + */ +void kill_pipe(struct pipe *p); + +/* put back a unused pipe into the live pool. If it still has data in it, it is + * closed and not reinjected into the live pool. The caller is not allowed to + * use it once released. + */ +void put_pipe(struct pipe *p); + +#endif /* _PROTO_PIPE_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/include/types/pipe.h b/include/types/pipe.h new file mode 100644 index 000000000..12a1eeee9 --- /dev/null +++ b/include/types/pipe.h @@ -0,0 +1,45 @@ +/* + include/types/pipe.h + Pipe management. + + Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, version 2.1 + exclusively. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _TYPES_PIPE_H +#define _TYPES_PIPE_H + +#include + +/* A pipe is described by its read and write FDs, and the data remaining in it. + * The FDs are valid if there are data pending. The user is not allowed to + * change the FDs. + */ +struct pipe { + int data; /* number of bytes present in the pipe */ + int prod; /* FD the producer must write to ; -1 if none */ + int cons; /* FD the consumer must read from ; -1 if none */ + struct pipe *next; +}; + +#endif /* _TYPES_PIPE_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/src/pipe.c b/src/pipe.c new file mode 100644 index 000000000..ee6c92c9d --- /dev/null +++ b/src/pipe.c @@ -0,0 +1,109 @@ +/* + * Pipe management + * + * Copyright 2000-2009 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include + +#include +#include + +#include +#include + +struct pool_head *pool2_pipe = NULL; +struct pipe *pipes_live = NULL; /* pipes which are still ready to use */ +int pipes_used = 0; /* # of pipes in use (2 fds each) */ +int pipes_free = 0; /* # of pipes unused */ + +/* allocate memory for the pipes */ +static void init_pipe() +{ + pool2_pipe = create_pool("pipe", sizeof(struct pipe), MEM_F_SHARED); + pipes_used = 0; + pipes_free = 0; +} + +/* return a pre-allocated empty pipe. Try to allocate one if there isn't any + * left. NULL is returned if a pipe could not be allocated. + */ +struct pipe *get_pipe() +{ + struct pipe *ret; + int pipefd[2]; + + if (likely(pipes_live)) { + ret = pipes_live; + pipes_live = pipes_live->next; + pipes_free--; + pipes_used++; + return ret; + } + + if (pipes_used >= global.maxpipes) + return NULL; + + ret = pool_alloc2(pool2_pipe); + if (!ret) + return NULL; + + if (pipe(pipefd) < 0) { + pool_free2(pool2_pipe, ret); + return NULL; + } + ret->data = 0; + ret->prod = pipefd[1]; + ret->cons = pipefd[0]; + ret->next = NULL; + pipes_used++; + return ret; +} + +/* destroy a pipe, possibly because an error was encountered on it. Its FDs + * will be closed and it will not be reinjected into the live pool. + */ +void kill_pipe(struct pipe *p) +{ + close(p->prod); + close(p->cons); + pool_free2(pool2_pipe, p); + pipes_used--; + return; +} + +/* put back a unused pipe into the live pool. If it still has data in it, it is + * closed and not reinjected into the live pool. The caller is not allowed to + * use it once released. + */ +void put_pipe(struct pipe *p) +{ + if (p->data) { + kill_pipe(p); + return; + } + p->next = pipes_live; + pipes_live = p; + pipes_free++; + pipes_used--; +} + + +__attribute__((constructor)) +static void __pipe_module_init(void) +{ + init_pipe(); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */