ypserv performance improvements:
- There are two cases where the server can potentially block for a long time while servicing a request: when handling a yp_all() request, which could take a while to complete if the map being transfered is large (e.g. 'ypcat passwd' where passwd.byname has 10,000 entries in it), and while doing DNS lookups when in SunOS compat mode (with the -dns flag), since some DNS lookups can take a long time to complete. While ypserv is blocked, other clients making requests to the server will also block. To fix this, we fork() ypall and DNS lookups into subprocesses and let the parent ypserv process go on servicing other incoming requests. We place a cap on the number of simultaneous processes that ypserv can fork (set at 20 for now) and go back to 'linear mode' if it hits the limit (which just means it won't fork() anymore until the number of simultaneous processes drops under 20 again). The cap does not apply to fork()s done as a result of ypxfr calls, since we want to do our best to insure that map transfers from master servers succeed. To make this work, we need our own special copy of svc_run() so that we can properly terminate child processes once the RPC dispatch functions have run. (I have no idea what SunOS does in this situation. The only other possibility I can think of is async socket I/O, but that seems like a headache and a half to implement.) - Do the politically correct thing and use sigaction() instead of signal() to install the SIGCHLD handler and to ignore SIGPIPEs. - Doing a yp_all() is sometimes slow due to the way read_database() is implemented. This is turn is due to a certain deficiency in the DB hash method: the R_CURSOR flag doesn't work, which means that when handed a key and asked to return the key/data pair for the _next_ key in the map, we have to reset the DB pointer to the start of the database, step through until we find the requested key, step one space ahead to the _next_ key, and then use that. (The original ypserv code used GDBM has a function called gdbm_nextkey() that does this for you.) This can get really slow for large maps. However, when doing a ypall, it seems that all database access are sequential, so we can forgo the first step (the 'search the database until we find the key') since the database should remain open and the cursor should be positioned at the right place until the yp_all() call finishes. We can't make this assumption for arbitrary yp_first()s and yp_next()s however (since we may have requests from several clients for different maps all arriving at different times) so those we have to handle the old way. (This would be much easier if R_CURSOR really worked. Maybe I should be using something other than the hash method.)
This commit is contained in:
parent
afdd6e6485
commit
e1086b16a9
@ -1,11 +1,11 @@
|
||||
# $Id: Makefile,v 1.5 1995/02/04 21:31:58 wpaul Exp $
|
||||
# $Id: Makefile,v 1.6 1995/02/15 04:33:52 wpaul Exp $
|
||||
# From: @(#)Makefile 8.3 (Berkeley) 4/2/94
|
||||
|
||||
PROG= ypserv
|
||||
SRCS= dnslookup.c yp_svc.c yp_xdr.c server.c
|
||||
SRCS= dnslookup.c svc_run.c yp_svc.c yp_xdr.c server.c
|
||||
|
||||
CFLAGS+=-Wall -DTCP_WRAPPER=0 -DTCPW_FACILITY=LOG_AUTH
|
||||
CFLAGS+=-DINSTDIR='"/usr/libexec"'
|
||||
CFLAGS+=-DMAX_CHILDREN=20 -DINSTDIR='"/usr/libexec"'
|
||||
|
||||
MAN8= ypserv.8
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
** Ported to FreeBSD and hacked all to pieces
|
||||
** by Bill Paul <wpaul@ctr.columbia.edu>
|
||||
**
|
||||
** $Id: server.c,v 1.6 1995/05/30 05:05:35 rgrimes Exp $
|
||||
** $Id: server.c,v 1.7 1995/07/02 18:48:21 wpaul Exp $
|
||||
**
|
||||
*/
|
||||
|
||||
@ -86,7 +86,8 @@ extern int errno;
|
||||
|
||||
int debug_flag = 0;
|
||||
int dns_flag = 0;
|
||||
|
||||
int children = 0;
|
||||
int forked = 0;
|
||||
|
||||
void verr(fmt, ap)
|
||||
const char *fmt;
|
||||
@ -310,6 +311,7 @@ static DB *open_database(const char *domain,
|
||||
|
||||
#define F_ALL 0x01
|
||||
#define F_NEXT 0x02
|
||||
#define F_YPALL 0x08
|
||||
|
||||
/*
|
||||
** Get a record from a DB database.
|
||||
@ -338,10 +340,13 @@ int read_database(DB *dbp,
|
||||
/*
|
||||
** This crap would be unnecessary if R_CURSOR actually worked.
|
||||
*/
|
||||
(dbp->seq)(dbp,&ckey,&dummyval,R_FIRST);
|
||||
while(strncmp((char *)ikey->data,ckey.data,(int)ikey->size) ||
|
||||
ikey->size != ckey.size)
|
||||
(dbp->seq)(dbp,&ckey,&dummyval,R_NEXT);
|
||||
if (flags < F_YPALL)
|
||||
{
|
||||
(dbp->seq)(dbp,&ckey,&dummyval,R_FIRST);
|
||||
while(strncmp((char *)ikey->data,ckey.data,(int)ikey->size) ||
|
||||
ikey->size != ckey.size)
|
||||
(dbp->seq)(dbp,&ckey,&dummyval,R_NEXT);
|
||||
}
|
||||
if ((dbp->seq)(dbp,&ckey,&dummyval,R_NEXT))
|
||||
ckey.data = NULL;
|
||||
free(dummyval.data);
|
||||
@ -523,13 +528,21 @@ ypresp_val *ypproc_match_2_svc(ypreq_key *key,
|
||||
** Do the jive thing if we didn't find the host in the YP map
|
||||
** and we have enabled the magic DNS lookup stuff.
|
||||
**
|
||||
** XXX Perhaps this should be done in a sub-process for performance
|
||||
** reasons. Later.
|
||||
** DNS lookups are handled in a subprocess so that the server
|
||||
** doesn't block while waiting for requests to complete.
|
||||
*/
|
||||
if (result.stat != YP_TRUE && strstr(key->map, "hosts") && dns_flag)
|
||||
{
|
||||
char *cp = NULL;
|
||||
|
||||
if (children < MAX_CHILDREN && fork())
|
||||
{
|
||||
children++;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
forked++;
|
||||
|
||||
key->key.keydat_val[key->key.keydat_len] = '\0';
|
||||
|
||||
if (debug_flag)
|
||||
@ -788,13 +801,14 @@ static void print_ypmap_parms(const struct ypmap_parms *pp)
|
||||
|
||||
|
||||
/*
|
||||
** Clean up after ypxfr child processes signal their termination.
|
||||
** Clean up after child processes signal their termination.
|
||||
*/
|
||||
void reapchild(sig)
|
||||
int sig;
|
||||
{
|
||||
int st;
|
||||
|
||||
children--;
|
||||
wait3(&st, WNOHANG, NULL);
|
||||
}
|
||||
|
||||
@ -865,7 +879,6 @@ ypresp_xfr *ypproc_xfr_2_svc(ypreq_xfr *xfr,
|
||||
result.xfrstat = YPXFR_XFRERR;
|
||||
default:
|
||||
{
|
||||
signal(SIGCHLD, reapchild);
|
||||
result.xfrstat = YPXFR_SUCC;
|
||||
break;
|
||||
}
|
||||
@ -926,7 +939,7 @@ static int ypall_encode(ypresp_key_val *val,
|
||||
dkey.data = val->key.keydat_val;
|
||||
dkey.size = val->key.keydat_len;
|
||||
|
||||
val->stat = read_database((DB *) data, &dkey, &okey, &dval, F_NEXT);
|
||||
val->stat = read_database((DB *) data, &dkey, &okey, &dval, F_NEXT | F_YPALL);
|
||||
|
||||
if (val->stat == YP_TRUE)
|
||||
{
|
||||
@ -970,6 +983,14 @@ ypresp_all *ypproc_all_2_svc(ypreq_nokey *nokey,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (children < MAX_CHILDREN && fork())
|
||||
{
|
||||
children++;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
forked++;
|
||||
|
||||
__xdr_ypall_cb.u.encode = NULL;
|
||||
__xdr_ypall_cb.u.close = NULL;
|
||||
__xdr_ypall_cb.data = NULL;
|
||||
|
81
gnu/usr.sbin/ypserv/svc_run.c
Normal file
81
gnu/usr.sbin/ypserv/svc_run.c
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
|
||||
* unrestricted use provided that this legend is included on all tape
|
||||
* media and as a part of the software program in whole or part. Users
|
||||
* may copy or modify Sun RPC without charge, but are not authorized
|
||||
* to license or distribute it to anyone else except as part of a product or
|
||||
* program developed by the user.
|
||||
*
|
||||
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
|
||||
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
|
||||
*
|
||||
* Sun RPC is provided with no support and without any obligation on the
|
||||
* part of Sun Microsystems, Inc. to assist in its use, correction,
|
||||
* modification or enhancement.
|
||||
*
|
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
|
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
|
||||
* OR ANY PART THEREOF.
|
||||
*
|
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
|
||||
* or profits or other special, indirect and consequential damages, even if
|
||||
* Sun has been advised of the possibility of such damages.
|
||||
*
|
||||
* Sun Microsystems, Inc.
|
||||
* 2550 Garcia Avenue
|
||||
* Mountain View, California 94043
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
/*static char *sccsid = "from: @(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";*/
|
||||
/*static char *sccsid = "from: @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC";*/
|
||||
static char *rcsid = "$Id: svc_run.c,v 1.2 1995/05/30 05:41:35 rgrimes Exp $";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is the rpc server side idle loop
|
||||
* Wait for input, call server program.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
extern int _rpc_dtablesize __P((void));
|
||||
|
||||
void
|
||||
my_svc_run()
|
||||
{
|
||||
#ifdef FD_SETSIZE
|
||||
fd_set readfds;
|
||||
#else
|
||||
int readfds;
|
||||
#endif /* def FD_SETSIZE */
|
||||
extern int errno;
|
||||
extern int forked;
|
||||
|
||||
for (;;) {
|
||||
#ifdef FD_SETSIZE
|
||||
readfds = svc_fdset;
|
||||
#else
|
||||
readfds = svc_fds;
|
||||
#endif /* def FD_SETSIZE */
|
||||
switch (select(_rpc_dtablesize(), &readfds, NULL, NULL,
|
||||
(struct timeval *)0)) {
|
||||
case -1:
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
perror("svc_run: - select failed");
|
||||
return;
|
||||
case 0:
|
||||
continue;
|
||||
default:
|
||||
svc_getreqset(&readfds);
|
||||
if (forked)
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
* And thus replied Lpd@NannyMUD:
|
||||
* Who cares? :-) /Peter Eriksson <pen@signum.se>
|
||||
*
|
||||
* $Id: yp_svc.c,v 1.4 1995/07/04 21:58:38 wpaul Exp $
|
||||
* $Id: yp_svc.c,v 1.5 1995/07/08 21:42:59 ats Exp $
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
@ -26,7 +26,9 @@
|
||||
#include <signal.h>
|
||||
|
||||
extern int errno;
|
||||
extern void Perror();
|
||||
extern void Perror __P((char *, ...));
|
||||
extern void my_svc_run __P((void));
|
||||
extern void reapchild __P((int));
|
||||
|
||||
#ifdef __STDC__
|
||||
#define SIG_PF void(*)(int)
|
||||
@ -263,6 +265,7 @@ int main(int argc, char **argv)
|
||||
struct sockaddr_in socket_address;
|
||||
int result;
|
||||
int sunos_4_kludge = 0;
|
||||
struct sigaction sa;
|
||||
|
||||
progname = strrchr (argv[0], '/');
|
||||
if (progname == (char *) NULL)
|
||||
@ -319,7 +322,10 @@ int main(int argc, char **argv)
|
||||
* Ignore SIGPIPEs. They can hurt us if someone does a ypcat
|
||||
* and then hits CTRL-C before it terminates.
|
||||
*/
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
sa.sa_handler = reapchild;
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
|
||||
(void) pmap_unset(YPPROG, YPVERS);
|
||||
if (sunos_4_kludge)
|
||||
@ -411,7 +417,7 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
svc_run();
|
||||
my_svc_run();
|
||||
Perror("svc_run returned");
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
|
Loading…
Reference in New Issue
Block a user